2013-12-16 49 views
3

我試圖如何在zip中打開一個unicode文本文件?

with zipfile.ZipFile("5.csv.zip", "r") as zfile: 
    for name in zfile.namelist(): 
     with zfile.open(name, 'rU') as readFile: 
       line = readFile.readline() 
       print(line) 
       split = line.split('\t') 

它回答:

b'$0.0\t1822\t1\t1\t1\n' 
Traceback (most recent call last) 
File "zip.py", line 6 
    split = line.split('\t') 
TypeError: Type str doesn't support the buffer API 

如何打開文本文件作爲unicode而不是作爲b

+0

它看起來像我的zip庫不支持「open」的編碼參數。如果這是正確的,我認爲你將不得不使用'codecs.EncodedFile'包裝或手動解碼每一行。 –

+0

我該怎麼做? –

+0

你知道文件的正確編碼嗎?它看起來像utf-8,但猜測你是否可以避免它是個壞主意。 –

回答

3

編輯對於Python 3,使用io.TextIOWrapper作爲J.F.Sebastian所描述的是最佳選擇。下面的答案可能對2.x有幫助。即使對於3.x,我也不認爲下面的任何內容都是不正確的,但io.TestIOWrapper仍然更好。

如果該文件是utf-8,這將工作:

# the rest of the code as above, then: 
with zfile.open(name, 'rU') as readFile: 
    line = readFile.readline().decode('utf8') 
    # etc 

如果你要超過你可以使用codecs.iterdecode文件迭代,但不會與readline()工作。

with zfile.open(name, 'rU') as readFile: 
    for line in codecs.iterdecode(readFile, 'utf8'): 
     print line 
     # etc 

請注意,對於多字節編碼,這兩種方法都不一定安全。例如,little-endian UTF-16表示換行符b'\x0A\x00'。尋找換行符的不支持unicode的工具會錯誤地將其拆分,並在下一行保留空字節。在這種情況下,您必須使用不會嘗試通過換行符分割輸入的內容,例如ZipFile.read,然後一次解碼整個字節串。這不是UTF-8的問題。

+0

我檢查過並確實'.readline()。decode('utf-16')'失敗,出現異常。更糟糕的是,'codecs.iterdecode()'悄悄地產生錯誤的輸出(換行符被移動到下一行)。 ['io.TextIOWrapper()'](http://stackoverflow.com/a/20603185/4279)避免了這樣的問題。 – jfs

1

您看到該錯誤的原因是您嘗試將字節與unicode混合在一起。到split的參數也必須是字節字符串:

>>> line = b'$0.0\t1822\t1\t1\t1\n' 
>>> line.split(b'\t') 
[b'$0.0', b'1822', b'1', b'1', b'1\n'] 

爲了得到一個unicode字符串,使用decode

>>> line.decode('utf-8') 
'$0.0\t1822\t1\t1\t1\n' 
6

要轉換一個字節流轉換爲Unicode流,你可以使用io.TextIOWrapper()

encoding = 'utf-8' 
with zipfile.ZipFile("5.csv.zip") as zfile: 
    for name in zfile.namelist(): 
     with zfile.open(name) as readfile: 
      for line in io.TextIOWrapper(readfile, encoding): 
       print(repr(line)) 

注意:TextIOWrapper()默認使用通用換行模式。 模式在zfile.open()從版本3.4開始已棄用。

它避免了在@Peter DeGlopper's answer中描述的多字節編碼問題。

+0

是的,如果這對於類文件對象起作用,那麼在打開文件時無法提供編碼的情況下(或者使用'codecs.open'方法),這可能是最安全的答案。)我已經看到了推薦使用它的建議'rU'模式,但是由於3.4還沒有出現,棄用警告似乎不適用。正確處理多字節換行符是一個令人信服的理由,即使沒有這樣做 - 但我想知道有多少與決定棄用有關? –

+0

它確實有效。它是*在Python 3中執行的方式。('subprocess'模塊中的sys.stdin,sys.stdout,(文本)管道是使用'TextIOWrapper'創建的)。 'codecs.open'需要一個文件名(我沒有看到它對zipfile有什麼幫助)。 'codecs.getreader(encoding)(file_obj)'可能對Python 2有用。 – jfs

+0

是的,我在考慮一般情況 - 我沒有看到更好的zipfiles選項。也許我的評論措辭會更好,「因爲這對文件類對象起作用......」 –

相關問題