当你使用
fh = codecs.open(fname,'r','utf8')
fh.read()
返回一个 Unicode。如果你使用这个 unicode 并使用你的数据库驱动程序(例如 mysql-python)将数据插入到你的数据库中,那么驱动程序负责将 unicode 转换为字节。驱动程序正在使用由设置的编码
con.set_character_set('utf8')
如果你使用
fh = open(fname, 'r')
然后fh.read()
返回一个字节串。您将受到任何字节的摆布fname
。幸运的是,根据您的帖子,该文件以 UTF-8 编码。由于数据已经是一串字节,驱动程序不执行任何编码,只是将字节串原样传送给数据库。
无论哪种方式,相同的 UTF-8 编码字节字符串都会插入到数据库中。
让我们看一下定义codecs.open的源代码:
def open(filename, mode='rb', encoding=None, errors='strict', buffering=1):
if encoding is not None:
if 'U' in mode:
# No automatic conversion of '\n' is done on reading and writing
mode = mode.strip().replace('U', '')
if mode[:1] not in set('rwa'):
mode = 'r' + mode
if 'b' not in mode:
# Force opening of the file in binary mode
mode = mode + 'b'
file = __builtin__.open(filename, mode, buffering)
if encoding is None:
return file
info = lookup(encoding)
srw = StreamReaderWriter(file, info.streamreader, info.streamwriter, errors)
# Add attributes to simplify introspection
srw.encoding = encoding
return srw
特别注意如果设置了 no 会发生什么encoding
:
file = __builtin__.open(filename, mode, buffering)
if encoding is None:
return file
所以本质上与未设置编码时codecs.open
的内置相同。open
内置open
函数返回一个文件对象,其read
方法返回一个str对象。它根本不解码。
相反,当您指定编码时,将codecs.open
返回 aStreamReaderWriter
并srw.encoding
设置为encoding
。现在,当您调用StreamReaderWriter
'sread
方法时,通常会返回一个unicode对象。首先str对象必须使用指定的编码进行解码。
在您的示例中,str
对象是
In [19]: content
Out[19]: '\xe2\x80\x9cThank you.\xe2\x80\x9d'
如果您将编码指定为'ascii'
,则StreamReaderWriter
尝试content
使用'ascii'
编码进行解码:
In [20]: content.decode('ascii')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)
这并不奇怪,因为ascii
编码只能解码 0--127 范围内的字节,并且'\xe2'
中的第一个字节content
具有该范围之外的序数值。
具体而言:当您不指定编码时:
In [13]: with codecs.open(filename, 'r') as f:
....: content = f.read()
In [14]: content
Out[14]: '\xe2\x80\x9cThank you.\xe2\x80\x9d'
content
是一个str
。
当您指定有效编码时:
In [22]: with codecs.open(filename, 'r', encoding = 'utf-8') as f:
....: content = f.read()
In [23]: content
Out[23]: u'\u201cThank you.\u201d'
content
是一个unicode
。
当您指定无效编码时:
In [25]: with codecs.open(filename, 'r', 'ascii') as f:
....: content = f.read()
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)
你得到一个UnicodeDecodeError
.