使用 csv.DictWriter 输出内存中的 gzip 压缩 csv 文件?
Using csv.DictWriter to output an in-memory gzipped csv file?
我想使用 Python 的 csv
模块中的 DictWriter
生成使用 GZip 压缩的 .csv 文件。我需要全部在内存中执行此操作,因此无法使用本地文件。
但是,我在处理 Python 中每个模块的类型要求时遇到了麻烦 3. 假设我正确地获得了一般结构,我不能让两个模块一起工作,因为 DictWriter
需要写入 io.StringIO
缓冲区,而 GZip
需要 io.BytesIO
对象。
所以,当我尝试这样做时:
buffer = io.BytesIO()
compressed = gzip.GzipFile(fileobj=buffer, mode='wb')
dict_writer = csv.DictWriter(buffer, ["a", "b"], extrasaction="ignore")
我得到:
TypeError: a bytes-like object is required, not 'str'
并且尝试将 io.StringIO
与 GZip
一起使用也不起作用。我该怎么做?
一种迂回的方法是先将其写入 io.StringIO
对象,然后将内容转换回 io.BytesIO
:
s = io.StringIO()
b = io.BytesIO()
dict_writer = csv.DictWriter(s, ["a", "b"], extrasaction="ignore")
... # complete your write operations ...
s.seek(0) # reset cursor to the beginning of the StringIO stream
b.write(s.read().encode('utf-8')) # or an encoding of your choice
compressed = gzip.GzipFile(fileobj=b, mode='wb')
...
s.close() # Remember to close your streams!
b.close()
虽然正如@wwii 的评论所建议的那样,根据您的数据大小,也许更值得在 bytes
中编写您自己的 csv
。
您可以使用 io.TextIOWrapper
将文本流无缝转换为二进制流:
import io
import gzip
import csv
buffer = io.BytesIO()
with gzip.GzipFile(fileobj=buffer, mode='wb') as compressed:
with io.TextIOWrapper(compressed, encoding='utf-8') as wrapper:
dict_writer = csv.DictWriter(wrapper, ["a", "b"], extrasaction="ignore")
dict_writer.writeheader()
dict_writer.writerows([{'a': 1, 'b': 2}, {'a': 4, 'b': 3}])
print(buffer.getvalue()) # dump the compressed binary data
buffer.seek(0)
dict_reader = csv.DictReader(io.TextIOWrapper(gzip.GzipFile(fileobj=buffer, mode='rb'), encoding='utf-8'))
print(list(dict_reader)) # see if uncompressing the compressed data gets us back what we wrote
这输出:
b'\x1f\x8b\x08\x00\x9c6[\\x02\xffJ\xd4I\xe2\xe5\xe52\xd41\x02\x92&:\xc6@\x12\x00\x00\x00\xff\xff\x03\x00\x85k\xa2\x9e\x12\x00\x00\x00'
[OrderedDict([('a', '1'), ('b', '2')]), OrderedDict([('a', '4'), ('b', '3')])]
我想使用 Python 的 csv
模块中的 DictWriter
生成使用 GZip 压缩的 .csv 文件。我需要全部在内存中执行此操作,因此无法使用本地文件。
但是,我在处理 Python 中每个模块的类型要求时遇到了麻烦 3. 假设我正确地获得了一般结构,我不能让两个模块一起工作,因为 DictWriter
需要写入 io.StringIO
缓冲区,而 GZip
需要 io.BytesIO
对象。
所以,当我尝试这样做时:
buffer = io.BytesIO()
compressed = gzip.GzipFile(fileobj=buffer, mode='wb')
dict_writer = csv.DictWriter(buffer, ["a", "b"], extrasaction="ignore")
我得到:
TypeError: a bytes-like object is required, not 'str'
并且尝试将 io.StringIO
与 GZip
一起使用也不起作用。我该怎么做?
一种迂回的方法是先将其写入 io.StringIO
对象,然后将内容转换回 io.BytesIO
:
s = io.StringIO()
b = io.BytesIO()
dict_writer = csv.DictWriter(s, ["a", "b"], extrasaction="ignore")
... # complete your write operations ...
s.seek(0) # reset cursor to the beginning of the StringIO stream
b.write(s.read().encode('utf-8')) # or an encoding of your choice
compressed = gzip.GzipFile(fileobj=b, mode='wb')
...
s.close() # Remember to close your streams!
b.close()
虽然正如@wwii 的评论所建议的那样,根据您的数据大小,也许更值得在 bytes
中编写您自己的 csv
。
您可以使用 io.TextIOWrapper
将文本流无缝转换为二进制流:
import io
import gzip
import csv
buffer = io.BytesIO()
with gzip.GzipFile(fileobj=buffer, mode='wb') as compressed:
with io.TextIOWrapper(compressed, encoding='utf-8') as wrapper:
dict_writer = csv.DictWriter(wrapper, ["a", "b"], extrasaction="ignore")
dict_writer.writeheader()
dict_writer.writerows([{'a': 1, 'b': 2}, {'a': 4, 'b': 3}])
print(buffer.getvalue()) # dump the compressed binary data
buffer.seek(0)
dict_reader = csv.DictReader(io.TextIOWrapper(gzip.GzipFile(fileobj=buffer, mode='rb'), encoding='utf-8'))
print(list(dict_reader)) # see if uncompressing the compressed data gets us back what we wrote
这输出:
b'\x1f\x8b\x08\x00\x9c6[\\x02\xffJ\xd4I\xe2\xe5\xe52\xd41\x02\x92&:\xc6@\x12\x00\x00\x00\xff\xff\x03\x00\x85k\xa2\x9e\x12\x00\x00\x00'
[OrderedDict([('a', '1'), ('b', '2')]), OrderedDict([('a', '4'), ('b', '3')])]