当你使用
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.