2013-12-16 52 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选项。也许我的评论措辞会更好,“因为这对文件类对象起作用......” –

相关问题