如何将表编码为字典列表直接写入包含CSV的压缩存档?



假设您有像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'

有没有人能想到一个变通的办法,或者可能是一个完全不同的方法,我没有看到?

基本约束是:

  1. d总是会被生成:这是我们无法决定或改变的
  2. 避免生成非常大的对象,因为它消耗的内存或磁盘空间与密集的pandas.DataFrame.from_dict()相同。
  3. 数据必须写入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.csvholding

a,b,c
1,,
,2,
,,3

最新更新