R语言下如何获得正确的文件编码

一个UTF-8的csv文件(可以在Windows下用notepad新建一个包含中文字符的文件,并在保存时编码选择UTF-8),在mac OS下读取没有任何问题,

> read.csv("~/tmp/utf8.txt")
[1] 测试
<0 rows> (or 0-length row.names)

同样的代码,在Windows下报错,

> read.csv("c:\\soft\\utf8.txt")
Error in make.names(col.names, unique = TRUE) : 
  invalid multibyte string 1

即使指定编码,输出仍然是乱码,

> read.csv("c:\\soft\\utf8.txt",fileEncoding = "UTF-8")
[1] X.
<0 行> (或0-长度的row.names)
Warning messages:
1: In read.table(file = file, header = header, sep = sep, quote = quote,  :
  invalid input found on input connection 'c:\soft\utf8.txt'
2: In read.table(file = file, header = header, sep = sep, quote = quote,  :
  incomplete final line found by readTableHeader on 'c:\soft\utf8.txt'

使用Linux下的file(检测文件编码及类型的程序),得到信息如下,

Stevens-MacBook-Pro:tmp steven$ file utf8.txt 
utf8.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators

网络搜索后,找到正确的解决办法,

> read.csv("c:\\soft\\utf8.txt",fileEncoding = "UTF-8-BOM")
[1] 测试
<0 行> (或0-长度的row.names)

没有想到,Windows下读取个文件还这么麻烦,得知道确切的编码,那有没有办法自动侦测编码或者简化工作呢?

把Linux的file编译为Windows下可以执行的程序,这样可以通过命令后的方法先获得文件的编码,或者把file.exe和magic.mgc(用于判断文件类型和编码的数据库文件)一起丢进Windows目录,然后使用下面两个命令中的一个,

> system("file c:\\soft\\utf8.txt")
c:\soft\utf8.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
> system2("file","c:\\soft\\utf8.txt")
c:\soft\utf8.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators

如果有多个文件,可以考虑把编码进行统一,推荐软件iconv 做批量编码转换。

当然你也可以下载笨重的Rtools(最新版本103M,包含了file,版本比较老,但不包含iconv)。

P.S.

网上寻找R语言版本的文件编码侦测包,寻找到了两个,wand Ruchardet ,

wand其实就是基于file做了简单的封装,但不能区分UTF-8 与 UTF-8-BOM(当然可以通过description来获得正确的版本信息,

> wand::incant("c:\\soft\\utf8.txt")
# A tibble: 1 × 5
                file  mime_type encoding                                               description extensions
               <chr>      <chr>    <chr>                                                     <chr>     <list>
1 c:\\soft\\utf8.txt text/plain    utf-8 UTF-8 Unicode (with BOM) text, with CRLF line terminators  <chr [8]>

 

Ruchardet 是mozilla的universalchardet port版,也是同样的问题,

> Ruchardet::detectFileEncoding("c:\\soft\\utf8.txt")
[1] "UTF-8"