Windows系统——读取编码为utf-8与utf-8-sig的文件区别

               Windows系统——读取编码为utf-8与utf-8-sig的文件区别

 

1、问题背景:

        相信很多细心的朋友在实战的过程中发现,Windows系统下,利用Python或者Java读取txt文件时,控制台打印首行正常,但如果用首行内容打开文本的话,就会报错。(换句话说,断点调试你会发现第一行多了一串字符 "\ufeff)。

        PS:Linux与MacOS系统是不存在这个问题的。(原因后面会说明)

        这个bug会导致什么问题呢?举个例子解释一下,假如文本test.txt中的内容如下(每行一个关键词):

中国加油
武汉加油

通常,我们习惯地使用编码"utf-8"来读取txt文件,以下是Python3的读取代码。(Java代码类似)

data = []
with open("test.txt", "r", encoding="utf-8") as file:
    for line in file:
        data.append(line.strip())
print("OK)

但是,断点调试却发现data的结果是:

['\ufeff中国加油', '武汉加油']

现在输入一个文本text = "中国加油",目标是查找text是不是在test.txt文件中,结果发现始终找不到,但是中国加油又确实在test.txt文件中,即得出一个结论:Windows系统下,利用txt词典对输入的text提取关键词,始终无法获取到txt文件的第一个词(第一行)。

 

2、解决方案:

将编码 utf-8 更改为 utf-8-sig 

 

3、原因:

首先,需要了解BOM的概念与几个规定。

(1)首行出现的"\ufeff"叫做字节顺序标记(ByteOrderMark,简称BOM),出现在文本文件头部,Unicode编码标准中用于标识文件是采用哪种格式的编码。(换言之:用来声明该文件的编码信息),参考BOM的百度百科。

(2)BOM是Unicode规范中推荐的标记字节顺序的方法。

  • 对于UTF-16,如果接收者收到的BOM是FEFF,表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。
  • UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明“我是UTF-8编码”。BOM的UTF-8编码是EF BB BF(用Notepad++或UltraEdit打开文本、切换到16进制可以看到)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

其次,看下"utf-8"与"utf-8-sig"的区别:

  • "utf-8"是以字节为编码单元,它的字节顺序在所有系统中都是一样的,没有字节序问题,因此它不需要BOM,所以当用"utf-8"编码方式读取带有BOM的文件时,它会把BOM当做是文件内容来处理,也就会发生以上问题。
  • "utf-8-sig"中sig全拼为 signature 也就是"带有签名的utf-8",因此"utf-8-sig"读取带有BOM的"utf-8文件时"会把BOM单独处理,与文本内容隔离开,也是我们期望的结果。

最后,在Windows下用文本编辑器创建的文本文件,如果选择以UTF-8等Unicode格式保存,会在文件头(第一个字符)加入一个BOM标识,"\ufeff",而Linux与MacOS系统中却不会在文件头加入BOM标识。所以在Windows系统下使用Python或者Java读取txt文件时,强烈建议如下

  • 读取:encoding="utf-8-sig"
  • 写入:encoding="utf-8" 或者 encoding="utf-8-sig"

PS:Linux与MacOS,不必担心这个问题

 

参考博客:

1、python 字符串转列表出现\ufeff的解决方法

2、Python 读取文件首行多了"\ufeff"字符串

你可能感兴趣的:(基础常识,python自学,python编程)