Python 2.7.1、编解码器和MySQLdb;为什么不需要设置文件编码
我有一个小型Python程序,它从文件中读入SQL语句并在MySQL数据库上运行它们。文件以UTF-8编码,数据库也使用UTF-8 如果我没有设置数据库编码,我会得到一个通常的错误,每个人都会问“latin-1”编解码器不能编码字符…”。因此,我使用Python 2.7.1、编解码器和MySQLdb;为什么不需要设置文件编码,python,unicode,python-2.7,mysql-python,codec,Python,Unicode,Python 2.7,Mysql Python,Codec,我有一个小型Python程序,它从文件中读入SQL语句并在MySQL数据库上运行它们。文件以UTF-8编码,数据库也使用UTF-8 如果我没有设置数据库编码,我会得到一个通常的错误,每个人都会问“latin-1”编解码器不能编码字符…”。因此,我使用 con.set_character_set('utf8') fh = codecs.open(fname,'r','utf8') 现在它可以工作了,但是当我不设置文件编码(或者只使用内置的open)时,它也可以工作,只是在数据库中。我所说的“工作
con.set_character_set('utf8')
fh = codecs.open(fname,'r','utf8')
现在它可以工作了,但是当我不设置文件编码(或者只使用内置的open)时,它也可以工作,只是在数据库中。我所说的“工作”是指结果数据库记录在假定为UTF-8的WordPress中正确显示
如果我想要魔法,我会用Ruby编写代码。Python在这种情况下做了什么?为什么不必告诉它文件编码
不用说,我在这方面做了很多搜索,我的GoogleFoo通常都很不错。在这里和博客上都有大量的帖子讨论了为什么有必要设置编码以及如何设置编码,但我还没有找到任何关于为什么它有时会起作用的帖子
编辑:
我使用一个包含“谢谢”的文件对此进行了一个简单的测试
file
E2 80 9C 54 68 61 6E 6B 20 79 6F 75 2E E2 80 9D
codecs utf8
201C 54 68 61 6E 6B 20 79 6F 75 2E 201D
试图用编解码器读取。open(myfile,'r','ascii')返回“UnicodeDecodeError:'ascii'编解码器无法解码字节0xe2”
从文件读取时产生了一个字节字符串,因此在插入数据库时似乎发生了奇迹 当您使用
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编码字节字符串插入数据库
让我们看一下定义以下内容的源代码: 请特别注意,如果未设置
编码
,会发生什么情况:
file = __builtin__.open(filename, mode, buffering)
if encoding is None:
return file
因此,当未设置编码时,codecs.open
与内置的open
基本相同。内置的open
返回一个file对象,其read
方法返回一个str对象。它根本不解码
相反,当指定编码时,codecs.open
返回StreamReaderWriter
,其中srw.encoding
设置为encoding
。现在,当调用StreamReaderWriter
的read
方法时,通常会返回一个unicode对象。首先,必须使用指定的编码对str对象进行解码
在您的示例中,str
对象是
In [19]: content
Out[19]: '\xe2\x80\x9cThank you.\xe2\x80\x9d'
如果将编码指定为'ascii'
,则StreamReaderWriter
将尝试使用'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'
(内容中的第一个字节)的序号值超出了该范围
对于具体性:当您不指定编码时:
In [13]: with codecs.open(filename, 'r') as f:
....: content = f.read()
In [14]: content
Out[14]: '\xe2\x80\x9cThank you.\xe2\x80\x9d'
In [22]: with codecs.open(filename, 'r', encoding = 'utf-8') as f:
....: content = f.read()
In [23]: content
Out[23]: u'\u201cThank you.\u201d'
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)
content
是一个str
指定有效编码时:
In [13]: with codecs.open(filename, 'r') as f:
....: content = f.read()
In [14]: content
Out[14]: '\xe2\x80\x9cThank you.\xe2\x80\x9d'
In [22]: with codecs.open(filename, 'r', encoding = 'utf-8') as f:
....: content = f.read()
In [23]: content
Out[23]: u'\u201cThank you.\u201d'
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)
content
是一种unicode
指定无效编码时:
In [13]: with codecs.open(filename, 'r') as f:
....: content = f.read()
In [14]: content
Out[14]: '\xe2\x80\x9cThank you.\xe2\x80\x9d'
In [22]: with codecs.open(filename, 'r', encoding = 'utf-8') as f:
....: content = f.read()
In [23]: content
Out[23]: u'\u201cThank you.\u201d'
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)
在Python的第4段中,您得到了一个UnicodeDecodeError,它是用than编写的,描述了codecs.open(filename,mode,[encoding])
函数,您正在使用:
encoding
是提供要使用的编码的字符串;如果保留为None,则返回一个接受8位字符串的常规Python文件对象
此外,在本书中,据说
(file.encoding
)也可以是无,在这种情况下,文件使用系统默认编码转换Unicode字符串
调用不带编码参数的codecs.open()
,返回的文件对象的编码属性为None
(已测试),因此使用Unicode的系统默认值,在您的情况下,该值必须是UTF-8。这就解释了为什么它在不显式的情况下工作得如此灵活。除了将文件提供给MySQL之外,您还对文件的内容做了什么吗?Python可以在UTF8中读取,使用常规的old-open就可以了。根据我的经验,当你试图把它写出来时,通常会出现“latin-1 codec can not encode”错误。我把结果数据库交给WordPress,它假设是UTF8。当它工作正常时,文本显示正常,当它不工作时,文本显示许多奇怪的字符。“用常规的旧版本阅读它很好”,这让我感到困惑,因为我认为默认编码是ISO 8859-1。@anov,谢谢,我已经在问题中添加了“works”的定义。我如何确定系统默认编码?使用open是否等同于使用codecs.open而不指定编码?当我使用内置的open()时,这是如何工作的?我已经编辑了问题以添加此内容。是的,使用open()
返回一个编码属性为None
的文件
对象,该属性与编解码器相同。在不带编码参数的情况下打开。通过执行sys.getdefaultencoding()
,可以找到系统默认编码。要更改它,请参见“谢谢”,我使用的是Mac,sys.getdefaultencoding()返回ascii。所以不清楚它为什么有效,我明白了。您能否从代码中提供更多信息,例如将fh
的内容发送到数据库的行