Python中的编码问题(encoding与decode、str与bytes)

1 引言

在文件读写及字符操作时,我们经常会出现下面这几种错误:

  • TypeError: write() argument must be str, not bytes
  • AttributeError: 'URLError' object has no attribute 'code'
  • UnicodeEncodeError: 'gbk' codec can't encode character '\xa0' inposition 5747: illegal multibyte sequence

这些错误一看就是编码问题, 本篇博文总结一下Python3文件读写及字符操作中的编码。

2 编码发展史

(1)ASCII编码
  众所周知,计算机只能处理0和1,任何符号都转换为0和1的序列才能处理。计算机中8个位(bit)作为一个字节,所以1个字节能产生2的8次方个0和1的不同组合,也就是说1个字节做多能表示256种字符。ASCII编码就是用1个字节来存储字符,计算机最初是美国人发明的,他们的符号不多,所以还将8个0和1序列中的第一位固定为0,ASCII只能表示127个字符。
  (2)GB2312编码
  美国佬的符号不多,所以ASCII编码够用,但是其他国家就不行了,每个国家符号数量都不一样,就各自指定了自己的编码。例如我们中国就制定了GB2312编码。GB2312编码用2个字节表示一个字符。
  (3)Unicode编码
  每个国家都用自己的编码,编码一朵就容易乱套,也没法交流,所以需要一种编码把各个国家的编码都囊括进去,这就是Unicode编码的由来。所以,Unicode也被称为万国码。Unicode编码也用2个字节存储一个字符。
  (4)utf-8编码
Unicode编码解决了编码不能通用的问题,但是却容易浪费内存,尤其是在存储英文的时候,例如一个字符“A”,ASCII编码只需要1个字节就够,但是Unicode编码必须要用2个字节。为了解决这一问题,就有了utf-8编码。 utf-8编码把存储英文依旧用一个字节,汉字就3个字节。特别是生僻的编程4-6字节,如果传输大量英文,utf-8作用就很明显了。
utf-8编码进行存储时有极大地优势,但是当读取到计算机内存时却不大合适,因为utf-8编码是变长的,不方便寻址和索引,所以在计算机内存中,还是转化为Unicode编码合适些。这就可以解释为什么每次读取文本时,要将编码转化为Unicode编码,而将内存中的字符写入文件存储时,要将编码转化为utf-8了。

3 str与bytes

Python中的编码问题(encoding与decode、str与bytes) 

Python中的编码问题(encoding与decode、str与bytes)

4 文件编码

在python 3 中字符是以Unicode的形式存储的,当然这里所说的存储是指存储在计算机内存当中,如果是存储在硬盘里,Python 3的字符是以bytes形式存储,也就是说如果要将字符写入硬盘,就必须对字符进行encode。对上面这段话再解释一下,如果要将str写入文件,如果以‘w’模式写入,则要求写入的内容必须是str类型;如果以‘wb’形式写入,则要求写入的内容必须是bytes类型。文章开头出现的集中错误,就是因为写入模式与写入内容的数据类型不匹配造成的。

s1 = '你好,安科网www.linuxidc.com'
#如果是以‘w’的方式写入,写入前一定要进行encoding,否则会报错 
with open('linuxidc.txt','w',encoding='utf-8') as f1:
    f1.write(s1)
s2 = s1.encode("utf-8")#转换为bytes的形式
#这时候写入方式一定要是‘wb’,且一定不能加encoding参数
with open('linuxidc.com.txt','wb') as f2:
    f2.write(s2)

5 网页编码

网页编码和文件编码方法差不多,如下urlopen下载下来的网页read()且用decoding(‘utf-8’)解码,那就必须以‘w’的方式写入文件。如果只是read()而不用encoding(‘utf-8’)进行编码,一定要以‘wb’方式写入:
  以‘w’方式写入时:

相关推荐