一、缘起
有一些文件整体上算是GBK编码,但有个别字符不属于GBK字符集。用记事本打开这样的文本文件,点击“文件-->另存为”菜单的时候,发现保存文件的默认编码方式是“gbk”。显然,我们用Python打开这样的文本文件的时候,很自然地,会采用"gbk"编码方式去打开文件,但是这样打开文件在读取的时候就会出错。今日小编分享一个读取这样的文本文件的小技巧。
二、环境
Win 7中文专业版 32位 + Python 3.64
三、准备
如下的例句节选自网络文本《倚天屠龙记》三十八:君子可欺之以方。
===============例句开始,例句内容不包含本行================
接着执法长老又胜了“梅花刀”的掌门人,连胜两阵
===============例句结束,例句内容不包含本行================
这个例句中的“接着执法长老”当中有一个字符“”,它的ANSI编码是十六进制的“FD A8”,这个编码不是GBK字符集中的有效编码。我们将上述例句保存为文本文件“test.txt”。
四、常规读取
因为文本文件“test.txt”当中包含了一个不在gbk字符集范围内的字符,所以用Python3.6的常规方法打开这个文本文件读取会报错。代码如下:
def read_txt_file(fn):
fp = open(fn)
for line in fp:
print(line, end = "")
fp.close()
read_txt_file("test.txt")
出错信息如下:
UnicodeDecodeError: 'gbk' codec can't decode byte 0xfd in position 4: illegal multibyte sequence
由于在中文Windows 7操作系统下,Python读取文件的默认编码是"gbk"编码,所以打开文件的diamante相当于是
fp = open(fn, encoding = "gbk")
但是Python读取的时候碰到一个非gbk字符集的字符,所以就报错了。将参数encoding = "gbk"显式地指定也一样报错,将gbk改成gb2312编码也无用。
五、忽略读取错误
网上看到一种办法是加个errors = "ignore"参数来忽略读取错误。
修改代码成如下样子:
def read_txt_file(fn):
fp = open(fn, errors = "ignore")
for line in fp:
print(line, end = "")
fp.close()
read_txt_file("test.txt")
读取文件时,不报错了,但是,读出的数据当中,那个非gbk字符集的字符后面一大部分汉字变成乱码了,原文本
接着执法长老又胜了“梅花刀”的掌门人,连胜两阵
变成了乱码文本
接着ㄖ捶ǔだ嫌质ち恕懊坊ǖ丁钡恼泼湃耍连胜两阵
六、用二进制方法读取
网上看到另一种方法,用二进制读取,解码为"ansi"编码。
继续修改代码如下:
def read_txt_file(fn):
fp = open(fn, "rb")
content = fp.read()
content = content.decode("ansi") # 注意,写"gbk"不行,"ansi"才可以
for line in content.split("\n"):
print(line)
fp.close()
read_txt_file("test.txt")
奇迹出现了,原来是读出了一段乱码,现在读出之后不乱了。原文本:
接着执法长老又胜了“梅花刀”的掌门人,连胜两阵
读出来之后:
接着执法长老又胜了“梅花刀”的掌门人,连胜两阵
跟原文一样。很好。
七、思考
仔细观察一下上面的代码,发现先是用二进制读出,然后再用"ansi"解码,那么,我们直接指定用"ansi"编码打开文本文件行不行呢?
继续修改代码:

发现运行结果跟前面先二进制读出再用"ansi"解码得到的结果是一样的。
八、结论
小编发现,编码"ansi"有着其他编码方式不具备的优点:如果用其他编码方式打开文本文件出错的话,不妨试试"ansi"编码,说不定能收到奇效。
九、引申
不知道这是不是中文Windows操作系统下面用Python读取中文文本文件时特有的解决办法,反正目前来看效果是不错的。
前面的推文曾提到用自定义函数来判定文本文件的编码,小编今天突然心血来潮想用来测试了一下这里的“test.txt”,它居然给我判断成了“unkown”。本来编写自动判断文本文件编码的函数就是为了用它判断出来的编码去打开文件,现在居然出了这个“unkown”的BUG,谁还敢用它来打开文件呢?所以,那个函数还是需要完善的。




