Posts /

GBK or UTF-8?Windows平台Python3读写文件

Twitter Facebook Google+
08 Nov 2017

想不到,我在简书正式写的第一篇文章,居然是关于代码的。

问题

昨晚,在Windows 10 平台上编写一个Python3程序时,需要打开一个文件并从中读取一定内容。

按照我之前的做法,无非是:

with open("xx.txt","r") as file:
  data=file.read()

然而,这一次,问题出现了:

文件中含有的一个字符”½”,并不能正常显示,在Python3中用print()打印出来,显示为:”陆”。

显然,出现了编码问题。

何以如此?

首先,由于Windows 平台的默认编码是GBK,而所打开的文件编码是UTF-8,很有可能是混淆了两者编码方式,从而出错。那么,我查询了”陆”和”½”这两个字符的多种编码方式,如下:

字符 GBK UTF-8 Unicode
C2BD E99986 9646
½ C2BD BD

可以发现,”½”的UTF-8编码和”陆”的GBK编码结果一致。

这也就解释了为什么”½”会变成”陆”:文件中”½”的UTF-8编码被错误地当作GBK编码来解释,从而产生了”陆”。

然而,为什么会这样呢?为什么文件中的其他字符并不会产生这样的错误呢?

以字符”K”、”7”、”。”、”辄”为例(分别代表英文字符、数字、中文符号、中文字符)比较它们的编码:

字符 GBK UTF-8 Unicode
K 4B 4B 4B
7 37 37 37
A1A3 E38082 3002
E9FC E8BE84 8F84

可以看出,对于原生的ASCII字符,其GBK和UTF-8编码完全一致,所以不会产生任何问题,即便混淆了编码方式;但是对于非ASCII字符,如中文字符,其GBK编码占用2个字节,UTF-8编码占用3个字节,且两者完全不一致,故混淆编码方式会出现错误。

比如,倘若文件内容是”无辄”,按照本文开头的方式打开此文件,会变成”鏃犺緞”;倘若文件内容是”辄”,则会抛出UnicodeDecodeError错误。

原因很简单,”无辄”的UTF-8编码结果有6个字节,被错误地解释为3个GBK编码的字符;而”辄”仅3个字节,无法按照GBK编码理解,因此直接报错。

而”½”更为特殊的是,不同于一般的中文字符,它的UTF-8编码是2个字节,因此被错误地用GBK打开时并不会报错。

如何解决?

不妨先查阅一下Python3中关于open()函数的说明,在Python交互界面中输入:

help(open)

结果如下(已省略无关内容):

Help on built-in function open in module io:

open(file, mode=’r’, buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

encoding is the name of the encoding used to decode or encode the file. This should only be used in text mode. The default encoding is platform dependent, but any encoding supported by Python can be passed. See the codecs module for the list of supported encodings.

注意加粗部分,在不指定encoding参数时,open()函数默认采用和系统相关的编码方式。而在Windows 系统下,系统相关的编码方式是GBK,不是UTF-8。

这便是产生错误的根源。

那么,解决方法也很简单,只需要指定encoding=”utf8”即可。

with open("xx.txt","r",encoding="utf8") as file:
  data=file.read()

从此天下太平。

反思

虽然Python3中的str采用Unicode编码方式,相比于Python2对于中文的支持有了很大的提升,但为了尽可能地减少麻烦,在涉及到中文或其他非ASCII字符时,务必记得设定编码方式为UTF-8。

尤其是在Windows 平台。


Twitter Facebook Google+