|
|
|
|
 一个内建函数open()的诡异的问题 - zjsflyer [ 2006-01-22 22:58 | 2,149 byte(s)]
 Re: 一个内建函数open()的诡异的问题 - Aryang [ 2006-03-11 11:21 | 8 byte(s)]
 Re: 一个内建函数open()的诡异的问题 - oyster [ 2006-01-24 11:57 | 189 byte(s)]
 Re: 一个内建函数open()的诡异的问题 - zjsflyer [ 2006-01-23 02:43 | 2,568 byte(s)]
 Re: 一个内建函数open()的诡异的问题 - panhudie [ 2006-01-23 18:19 | 323 byte(s)]
 Re: 一个内建函数open()的诡异的问题 - zjsflyer [ 2006-01-23 21:14 | 1,028 byte(s)]
|
|
|
|
[Original]
[Print]
[Top]
|
open()函数有时候的表现让人匪夷所思....请看下面例子
环境:windows xp,python 2.4.2
现在有三个文本,分别如下
文件名------------文件内容------字符编码-----------------十六进制编辑模式下的编码(ultraEdit有这个功能)
【ascii.txt】----- abcd----------- ASCII编码--------------- 61 62 63 64
【utf.txt】--------中国a---------- UTF-16-le编码--------- FFFE 2D4E FD56 6100
【gbk.txt】-------中国a---------- GBK编码----------------D6D0 B9F9 61
python内建的 open(filename[,mode[,buffer]]) 函数是用来打开,读写文件的
例如在python自带的IDLE编辑器下写入
>>>myFile = open('d:\temp\ascii.txt', mode='rb')
>>>data = myFile.read()
>>>data
'abcd'
>>>myFile = open('d:\temp\gbk.txt', mode='rb')
>>>data = myFile.read()
>>>data
'xd6 xd0 xb9 xfa a'
但让我觉得不可思议的是下面这个
>>>myFile = open('d:\temp\utf.txt', mode='rb')
>>>data = myFile.read()
>>>data
'xe4xb8xadxe5x9bxbda' #这是“中国a”的utf-8的字符编码
诡异之处在于,以二进制方式打开的utf-16-le(这是windowsNT,2000,Xp下的缺省的unicode编码)
居然在open函数打开的file对象上执行read()方法时自动的转换成了utf-8 的编码了
我一直以为python中的file对象是比较“傻”的,想不到他还能转换编码??? 最麻烦的是,他只能转换
utf-16到utf-8,对别的编码就是按二进制一个字节一个字节老老实实读入...
那以后编写程序时不得不对要读取的文件进行判断,utf-16是一种情况,其他的又是另一种情况,这都麻烦啊,而且有时候你根本不知道读入的文件的编码,那时怎么办?
不知道有没有那位达人解释一下这是怎么回事? 这算不算python的一个bug?
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
呵呵,又高了一个下午,已经搞清楚了...只能说windows平台下的utf-8编码的unicode文件相当复杂...
居然有三种之多,utf-8号称所以平台都是一样的,但一旦涉及到如何构建一个内容是utf-8编码的文本文件的问题
时,就不是那么回事了.... 以下以windows XP,python2.4.2unicode版本为例,并且假设文件内容都是
“中国a”
1. 用‘记事本’创建,且选择“文件”-->“另存为”,编码选择“UTF-8”.
它的特点是会在文件前隐含增加三个字节“EF BB BF”,只要你用python中的open()并选择二进制模式
打开时,你就会发现它的内容是'xef xbb xbf xe4 xb8 xad xe5 x9b xbd a',
最搞笑的是当你用UltraEditor来打开它,同时右键菜单中选择“Hex 编辑”时,你会发现这个文本的内容居然是“FF FE 2D4E FE56 6100”,这居然和这个文件的utf-16-le的编码完全一样,搞得我最开始还以为记事本不能创建真正的utf-8的文本文件了...
2.用UltraEditor创建,而且选择“文件”-->“转换”-->“ASCII转UTF-8(unicode编辑)”,还有用python中
的 codecs.open(filename, mode='wb', encoding='utf-8') 函数创建的文件是一样的,特点如下
这中utf-8文件不会在在文件前隐含增加三个字节“EF BB BF”,只要你用python中的open()并选择二进制
模式打开时,你就会发现它的内容是'xe4 xb8 xad xe5 x9b xbd a',
同样当你用UltraEditor的”Hex 编辑“来打开它时,你会发现和第一中情况一样,这个文本的内容是“FF FE 2D4E FE56 6100”
3.用UltraEditor创建,而且选择“文件”-->“转换”-->“Unicode/ASCII/UTF-8/转UTF-8(ASCII编辑)“
它的特点是在文本中就是变长字节的utf-8编码,这才像真正的utf-8文档...哈哈
用python中的open()并选择二进制模式打开时,你就会发现它的内容是'xe4 xb8 xad xe5 x9b xbd a',
但当你用UltraEditor的”Hex 编辑“来打开它时,这个文本的内容是“E4B8AD E59BBD 61”
别看这三种utf-8文件都有不相同的地方,但当你在Opera,IE中打开它们,同时选择编码为”UTF-8“时
你会发现他们都是真正的utf-8,因为都能正确显示为”中国a“,而选择UTF-16,GBK等内码时,就显示
为乱码...神了...哈哈.
不过值得庆幸的,utf-16不存在这样的问题...用ultraEditor,记事本,python的codecs.open(...,encoding='utf-16')三者创建的utf-16的文件都是一样的.....
这包括用用UltraEditor的”Hex 编辑“来打开它,和用python中的open()并选择二进制模式
打开时都是一致的...当然,因为是windows os的缘故,它们都是UTF-16-Le 的,即高位字节在后的方式
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
我用gvim试了下用hex模式打开utf16le的文件, 结果跟想的一样.
但是再换成text模式的时候, gvim就会用 根据你的encoding(我设的是cp936), 把文件转成cp936, 而不是utf16le了.
UltraEditor可能就是一开始就帮你转了.
google了下
EFBB 应该是表示utf8
FFFE 这个是utf16le
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
我想经过这两天的研究,我已经搞明白了Unicode的相关问题...
Unicode文件的头几个字节叫BOM,有两个功能,一是用来指明Unicode文件的编码具体是UTF-16,还是UTF-8,UTF-32的,二是如果是UTF-16或者UTF-32,则BOM可以进一步指出高低位字节的顺序的.
BOM 为 FF EF是,表明该文本文件是UTF-16-le 编码,这就是windowsNT,2000,xp缺省使用的unicode编码方式.
BOM 为EF FF是,表明该文本文件是UTF-16-be 编码
BOM 为EF BB BF时,表明该文件是UTF-8 编码
但这是规定,具体的程序完全可以不遵守的,你可以不在UTF-8编码的文件前加EF BB BF,一样没有问题...这就是python中用codecs.open(..., encoding='utf-8')建立的那种utf-8编码的Unicode文本文件...
而微软自己编写的记事本,当然遵循规范了,所以它创建的utf-8文件,前面是有EF BB BF
还有,UltraEditor的确是做了自动转换的工作,在HEX编辑方式下,它把UTF-8文件的ROM自动省略了(如果有的话),而且自动把UTF-8编码转换为UTF-16-Le来显示....这造成了我以前的那些困惑..
|
|
|
[Original]
[Print]
[Top]
|
|
[Original]
[Print]
[Top]
|
感谢你的分析
编码我始终没有弄清楚
上回用一个语言,源代码要求是utf-8编码,但是初始化指定字库和程序正文部分的uft-8又是不一样的,那个语言的发明者又死活不承认是bug,郁闷的很
|
|
|
[Original]
[Print]
[Top]
|
|
|