2009-06-01 74 views
145

我真的和codecs.open function混淆。當我這樣做:用Python寫入UTF-8文件

file = codecs.open("temp", "w", "utf-8") 
file.write(codecs.BOM_UTF8) 
file.close() 

它給我的錯誤

UnicodeDecodeError: 'ascii' codec can't decode byte 0xef in position 0: ordinal not in range(128)

如果我做的:

file = open("temp", "w") 
file.write(codecs.BOM_UTF8) 
file.close() 

它工作正常。

問題是爲什麼第一種方法失敗?我該如何插入骨頭?

如果第二種方法是正確的做法,使用codecs.open(filename, "w", "utf-8")的要點是什麼?

+40

不要在UTF-8使用一個BOM。 ***請。*** – tchrist 2012-02-09 11:12:46

+6

@tchrist Huh?爲什麼不? – 2013-06-01 05:16:33

+6

@SalmanPK BOM在UTF-8中不需要,只會增加複雜性(例如,您不能只連接BOM'd文件和結果與有效文本)。請參閱[本問答](http://stackoverflow.com/questions/2223882/whats-different-between-utf-8-and-utf-8-without-bom);千萬不要錯過Q – 2013-08-29 14:18:46

回答

213

我相信問題是codecs.BOM_UTF8是一個字節字符串,而不是一個Unicode字符串。我懷疑文件處理程序試圖猜測你真正的意思是基於「我打算把Unicode編寫成UTF-8編碼的文本,但你給了我一個字節串!」

試着寫Unicode字符串的字節順序標記(即Unicode的U + FEFF)直接,因此該文件只是編碼爲UTF-8:

import codecs 

file = codecs.open("lol", "w", "utf-8") 
file.write(u'\ufeff') 
file.close() 

(這似乎得到正確的答案 - 一個字節爲EF BB BF的文件)

編輯:使用「utf-8-sig」作爲編碼的S. Lott的suggestion比自己明確編寫BOM更好,但我會留下這個答案這裏解釋了之前發生了什麼問題。

+0

下的重大評論非常感謝,絕對讓事情更加清晰 – 2009-06-01 09:58:22

+0

警告:開放和開放不一樣。如果你「從編解碼器導入打開」,它不會像你只是輸入「打開」一樣。 – Shiki 2013-08-20 13:19:54

11

@ S-洛特給出正確的過程,但不斷擴大的的Unicode問題上,的Python解釋器可以提供更多的見解。

喬恩斯基特是正確的(異常)有關codecs模塊 - 它包含字節字符串:

>>> import codecs 
>>> codecs.BOM 
'\xff\xfe' 
>>> codecs.BOM_UTF8 
'\xef\xbb\xbf' 
>>> 

採摘另一個尼特,該BOM有一個標準的Unicode名稱,也可以輸入:

>>> bom= u"\N{ZERO WIDTH NO-BREAK SPACE}" 
>>> bom 
u'\ufeff' 

它也可以訪問通過unicodedata

>>> import unicodedata 
>>> unicodedata.lookup('ZERO WIDTH NO-BREAK SPACE') 
u'\ufeff' 
>>> 
5

我使用的文件* nix的命令到未知字符集轉換文件在UTF-8文件

# -*- encoding: utf-8 -*- 

# converting a unknown formatting file in utf-8 

import codecs 
import commands 

file_location = "jumper.sub" 
file_encoding = commands.getoutput('file -b --mime-encoding %s' % file_location) 

file_stream = codecs.open(file_location, 'r', file_encoding) 
file_output = codecs.open(file_location+"b", 'w', 'utf-8') 

for l in file_stream: 
    file_output.write(l) 

file_stream.close() 
file_output.close()