如何在Python 3中使用CSV Writers处理GZIP文件?

15

我正在尝试将一些代码从Python 2.7迁移到Python 3。2to3工具可以很好地处理基本语法和包更改,但现在我们遇到了一些奇怪的副作用。

我有以下代码块。它使用gzip模块打开一个临时文件名。

f = NamedTemporaryFile(delete=False)
f.close()
fn = f.name + '.gz'
os.rename(f.name, fn)
fz = gzip.open(fn, 'wb')
writer = csv.writer(fz, delimiter='\t', lineterminator=lt)
for row in table:
    writer.writerow(row)
fz.close()

问题在于执行此操作会报以下错误:
File "/usr/local/Cellar/python3/3.4.2_1/Frameworks/Python.framework/Versions/3.4/lib/python3.4/gzip.py", line 343, in write
self.crc = zlib.crc32(data, self.crc) & 0xffffffff
TypeError: 'str' does not support the buffer interface

我已尝试将gzip文件以“w”而非“wb”的方式打开,但没有成功。我猜测gzip模块期望一个字节数组,但CSV Writer不会提供除字符串外的其他内容。
人们如何在Python 3中实现这个呢?
编辑:我应该提到,这个代码块在Python 2.7中可以顺利执行。

你应该尝试以写入模式运行它。 fz = gzip.open(fn,'w',newline ='') - Tanveer Alam
不行,我得到了与上面相同的“ValueError”。我正在研究将其重构为一个GzipFile,该文件包装在TextIOWrapper中,根据文档。但是他们在这方面并没有提供很详细的信息。 - WineSoaked
3
将模式更改为wt,而不是wb - Mazdak
我把评论作为答案添加了!;) - Mazdak
另外,您可以使用 writer.writerows(table),而无需自己迭代其他 table - VMAtm
1个回答

36
你需要更改 gzip 的模式为 wt
fz = gzip.open(fn, 'wt')

同样,gzip.open()bz2.open()的一个鲜为人知的特性是它们可以在已经以二进制模式打开的文件之上进行分层。例如,这个例子可以正常工作:

import gzip
f = open('somefile.gz', 'rb')
with gzip.open(f, 'rt') as g:
    text = g.read()

这使得gzip和bz2模块可以与各种文件式对象一起使用,例如套接字、管道和内存文件。


没错,Python 3 版本中打开文件时需要非常非常小心标志位的使用。天哪,这真是个头疼的问题。 - WineSoaked
@WineSoaked :),是的,而且gzip.open()bz2.open()的一个鲜为人知的特性是它们可以在已经以二进制模式打开的现有文件之上进行分层。 - Mazdak
5
如果CSV中的一个条目包含换行符,则csv的换行处理可能会受到影响,因此您应该使用gzip.open(fn, 'wt', newline='')进行写入操作。请注意不要改变原来的意思。 - drevicko
如果在同一个脚本中你想要上传该文件,那么你需要关闭文件处理器 f,否则上传的 gzip 文件将会损坏。所以,在 with 块之后只需执行 f.close() 即可。 - Zoltan Fedor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接