编码
每个系统都有自己的默认编码,比如中国的windows默认gbk,linux默认是utf-8,显示各种界面化我们能看到的UI,都是使用的系统的编码。
而unicode是万国码,在它的基础上可以encode成各种别的国家的特有编码。
unicode.encode = utf8
utf8.decode = unicode
从写文件到读文件的流程:
- py写入文件,写文件都是二进制流,所以会先找写入方法的encoding类型做编码,如果方法没有指定就会找py默认的编码写入。(py2是ascii,py3是u8)。
- 写入后,打开文件,如果文件软件本身支持编码选择的,选择和文本写入的编码一样就会正常显示,否则乱码。如果文件使用的是系统编码,那系统的编码和文本写入的编码一样就会正常显示,否则乱码。
python2
在python2中,有unicode和str两种类型。我们在字符串前面加u,它的类型就是unicode,如果去掉u,那类型就是str。python2的str和bytes是一个东西,所以我们给字符串前面加b,其实type出来也是str类型。
读写文件时,如果我们把unicode的数据写入文本肯定会报错。因为字符串是 unicode,所以Python会(自动)先调用encode方法来编码unicode字符串,然后再写入文件,因为python2的open不能指定encoding类型,就按照默认的python2的编码ascii码,unicode->ascii码是有问题的所以报错了。
另外,python2的文件写入, open文件类型是不是b都无所谓,因为str和bytes本来就是一个东西,写入的都是二进制流。
总结:
- python2的编码有两种,一种是unicode,另一种是str,而bytes就是str。
- utf8,gbk等编码的类型是str,这样导致二进制方式的读写和普通方式读写没有区别的。
- 如果要把unicode类型的字符串写入文件,要看文件所在系统的编码,需要encode才能写入。否则按照python2默认的ascii编码就会报错。
python3
python3里去掉了unicode这种类型,增加了bytes类型。就是str和bytes两种类型,原来的unicode其实就是str类型。
我们在此str基础上encode,变成utf8,它的类型就是bytes。输出后会看见字符串前面有b的标志,这就是bytes类型。如果强行给b里写入汉字会报错,python3机制是bytes类型只支持固定的ascii码。
在python3中的文件读写是方便很多,首先在open函数里加入了encoding参数,可以在读写的同时根据本地电脑的编码对文本编码做适配。其次因为python3的默认编码是unicode,就算我们不指定也能按照u8编码。(这一步在2中是会报错的)
因为bytes类型的设置,导致有些库的调用我们需要传入二进制格式,这时我们要对参数做encode,在python2中因为bytes就是str是不需要处理的。
signature = rsa.sign(message.encode("UTF-8"), key, 'SHA-256')
hashlib.md5(message.encode(encoding='UTF-8')).hexdigest()
上面转换为utf8的目的,就是把它的类型转为方法要求的bytes,我们看看rsa的sign方法参数的定义:
def sign(message: bytes, priv_key: key.PrivateKey, hash_method: str) -> bytes:
总结:
- python3的编码类型有str和bytes两种,unicode类型就是str。utf8这些类型就是bytes。
- open函数新增encoding参数,可以对文本的读写做编码转化,避免乱码。(不写也行,就按照默认的u8编码)
- 网络传输的结果都是bytes,对于bytes的读写文件需要加wb或rb,str类型就是正常文件的读写。
- 函数传参要注意是bytes还是str,要对参数做相应的处理。