假设您有像d
这样的字典列表形式的数据:
d = [{'a' : 1, 'b' : 2}, {'a' : 3, 'c' : 5}]
,你想把它保存为一个逗号分隔的表到一个压缩的(不是gzip,我是说一个.zip存档)CSV而不经过,例如,pandas.DataFrame.from_dict()
。
为什么不通过pandas
?因为d
在实际实践中可能对应于一个非常大的,但特别是稀疏的, DataFrame,即每行有比非na数据更多列的表,由于某种原因占用了大量内存(顺便说一下,这不是一个理论:它使我们的脚本崩溃了几次,因此我们需要围绕它工作)。
d
是数据的一种非透视的伪装版本,因为每个字典只包含相关的数据,而不是无用的NA序列。
从csv
模块的文档中,我学会了如何将d
直接写入CSV:
with open('test.csv', 'w') as csvfile :
writer = csv.DictWriter(csvfile, fieldnames = ['a','b','c'])
writer.writeheader()
writer.writerows(d)
但是我没有看到任何选项可以写入压缩的CSV。
我查阅了zipfile
的文档,但由于文本和字节之间的常见问题,我无法使其工作。
if os.path.exists('test.csv.zip') :
os.remove('test.csv.zip')
with zipfile.ZipFile('test.csv.zip', mode = 'a') as zip :
with zip.open('test.csv', 'w') as csvfile :
writer = csv.DictWriter(csvfile, fieldnames = ['a','b','c'])
writer.writeheader()
writer.writerows(d)
# TypeError: a bytes-like object is required, not 'str'
有没有人能想到一个变通的办法,或者可能是一个完全不同的方法,我没有看到?
基本约束是:
d
总是会被生成:这是我们无法决定或改变的- 避免生成非常大的对象,因为它消耗的内存或磁盘空间与密集的
pandas.DataFrame.from_dict()
相同。 - 数据必须写入csv.zip归档文件。
否则我们会写入CSV,希望它不会太大(但是,是的,这是最初的问题,所以…),然后压缩它。
编辑为了完整,发布了Daweo的答案的实现。
import os
import zipfile
import csv
import codecs
utf8 = codecs.getwriter('utf_8') # or other encoding dictated by requirements
output_zip_file = 'test.csv.zip'
if os.path.exists(output_zip_file) :
os.remove(output_zip_file)
with zipfile.ZipFile(output_zip_file, mode = 'a') as zip :
with zip.open('out.csv', 'w') as csvfile :
writer = csv.DictWriter(utf8(csvfile), fieldnames = ['a','b','c'])
writer.writeheader()
writer.writerows(d)
如果您希望将csv.DictWriter
与二进制文件句柄一起使用,则可以使用codecs.StreamWriter
,请考虑以下简单示例
import csv
import codecs
utf8 = codecs.getwriter('utf_8') # or other encoding dictated by requirements
with open("file.csv","wb") as f:
writer = csv.DictWriter(utf8(f), fieldnames = ['a','b','c'])
writer.writeheader()
writer.writerows([{'a':1},{'b':2},{'c':3}])
创建file.csv
holding
a,b,c
1,,
,2,
,,3