如何将 zip 文件中的文件作为文本而不是字节读取?

新手上路,请多包涵

用于读取 ZIP 存档中的 CSV 文件的简单程序:

 import csv, sys, zipfile

zip_file    = zipfile.ZipFile(sys.argv[1])
items_file  = zip_file.open('items.csv', 'rU')

for row in csv.DictReader(items_file):
    pass

适用于 Python 2.7:

 $ python2.7 test_zip_file_py3k.py ~/data.zip
$

但不是在 Python 3.2 中:

 $ python3.2 test_zip_file_py3k.py ~/data.zip
Traceback (most recent call last):
    File "test_zip_file_py3k.py", line 8, in <module>
    for row in csv.DictReader(items_file):
    File "/somedir/python3.2/csv.py", line 109, in __next__
    self.fieldnames
    File "/somedir/python3.2/csv.py", line 96, in fieldnames
    self._fieldnames = next(self.reader)
_csv.Error: iterator should return strings, not bytes (did you open the file
in text mode?)

Python 3 中的 csv 模块想要查看文本文件,但是 zipfile.ZipFile.open 返回一个 zipfile.ZipExtFile 始终被视为二进制数据。

如何在 Python 3 中实现这一点?

原文由 Marc Abramowitz 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 692
2 个回答

我只是注意到 Lennart 的回答 不适用于 Python 3.1 ,但它 确实 适用于 Python 3.2 。他们在 Python 3.2 中增强了 zipfile.ZipExtFile (参见 发行说明)。这些更改似乎使 zipfile.ZipExtFileio.TextWrapper --- 配合得很好。

顺便说一下,它在 Python 3.1 中工作,如果你取消注释下面的 hacky 行到 monkey-patch zipfile.ZipExtFile ,并不是说我会推荐这种 hackery。我包含它只是为了说明在 Python 3.2 中所做的工作的本质,以使事情很好地工作。

 $ cat test_zip_file_py3k.py
import csv, io, sys, zipfile

zip_file    = zipfile.ZipFile(sys.argv[1])
items_file  = zip_file.open('items.csv', 'rU')
# items_file.readable = lambda: True
# items_file.writable = lambda: False
# items_file.seekable = lambda: False
# items_file.read1 = items_file.read
items_file  = io.TextIOWrapper(items_file)

for idx, row in enumerate(csv.DictReader(items_file)):
    print('Processing row {0} -- row = {1}'.format(idx, row))

如果我必须支持 py3k < 3.2,那么我会使用 其他答案 中的解决方案。

更新 3.6+

从 w/3.6 开始,删除了对 mode='U' 的支持 ^1

在 3.6 版中更改: 删除了对 mode='U' 的支持。使用 io.TextIOWrapper 以通用换行模式读取压缩文本文件。

从 w/3.8 开始,添加了一个 Path 对象,它为我们提供了一个 open() 我们可以调用的方法,就像内置的 open() 函数(传递 newline='' -ee-7286我们的 CSV 的例子),我们得到一个 io.TextIOWrapper 对象,csv 读者接受。 在此处 查看 Yuri 的回答。

原文由 Marc Abramowitz 发布,翻译遵循 CC BY-SA 4.0 许可协议

您可以将其包装在 io.TextIOWrapper 中。

 items_file  = io.TextIOWrapper(items_file, encoding='your-encoding', newline='')

应该管用。

原文由 Lennart Regebro 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进