Python如何将字典列表数据直接写入含CSV的zip压缩包
问题说明
现有如下字典列表格式的数据d:
d = [{'a' : 1, 'b' : 2}, {'a' : 3, 'c' : 5}]
需要将其转换为逗号分隔的CSV格式,存储在标准**.zip**(非gzip)归档内,且禁止使用pandas.DataFrame.from_dict()这类方法实现。
禁用pandas的原因是实际生产场景中,d可能对应体量极大的稀疏表:总列数远多于每行非空值的数量,这类稠密结构转换会占用极高内存,该问题已经多次导致脚本内存溢出崩溃,必须采用低内存占用的替代方案。d本身是隐式逆透视的存储结构,每个字典仅保存有效数据,不存储无意义的空值占位。csv模块官方文档给出了写入普通CSV文件的标准写法:
with open('test.csv', 'w') as csvfile : writer = csv.DictWriter(csvfile, fieldnames = ['a','b','c']) writer.writeheader() writer.writerows(d)
但文档没有提供直接写入zip压缩包内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文件,再压缩为zip,但临时文件体积过大正是最初遇到的核心问题,该方案不可行。
解决方案
报错的根本原因是:写入模式下zipfile.open()返回的文件对象仅接受字节类型输入,而csv.DictWriter输出的是字符串类型内容,只需要在两者之间增加一层编码包装层,即可实现全程流式写入,不需要生成磁盘临时文件,也不会在内存中加载全量稠密表,内存占用极低。
可直接运行的实现代码如下:
import os import zipfile import csv import codecs utf8_encoder = codecs.getwriter('utf_8') # 可根据需求替换为其他编码,比如gbk output_zip_path = 'test.csv.zip' if os.path.exists(output_zip_path) : os.remove(output_zip_path) # 创建新归档建议使用mode='w',追加内容到已有归档再用mode='a' with zipfile.ZipFile(output_zip_path, mode = 'w') as zf : with zf.open('result.csv', 'w') as raw_csv_file : # 给字节流包装一层编码层,接收字符串输入自动编码为字节 csv_file = utf8_encoder(raw_csv_file) writer = csv.DictWriter(csv_file, fieldnames = ['a','b','c']) writer.writeheader() writer.writerows(d)
内容的提问来源于stack exchange,提问作者user6376297
相关产品推荐
相关产品推荐

