Django/Python用xlsxwriter生成多工作簿打包zip时文件被覆盖丢失
问题根因
两个核心bug导致仅第二次迭代生成的Excel正常,首个文件丢失/损坏:
- 压缩包打开模式使用错误:给全新的空
BytesIO流用追加模式"a"初始化ZipFile,该模式仅用于向已存在的合法zip文件追加内容,空流使用"a"模式写入时,会破坏第一个文件条目的zip头结构,直接导致首个文件损坏丢失。 - 存储逻辑有隐患:列表里存的是
BytesIO流的对象引用,而非最终生成的文件字节,后续如果误操作流的指针位置、状态,会直接影响文件内容,内存流这类临时对象最好在生成完成后立刻读取为不可变的字节数据再存储。
修复方案
- 调整循环内的文件生成逻辑,Excel生成完成后直接读取字节内容存入列表,不持有流对象引用
- 修正ZipFile的初始化模式,新建压缩包使用写入模式
"w" - 移除冗余的手动关闭ZipFile的代码,上下文管理器会自动完成资源释放和内容刷入
修复后的核心代码如下:
报表生成循环段:
workBookList = [] SA = refModels.ServiceArea.objects.all() for service_area in SA: fileName = f"{service_area.name}.xlsx" output = BytesIO() book = Workbook(output, {'in_memory': True}) # 原有报表填充业务逻辑无需改动 book.close() output.seek(0) # 直接读取二进制内容存入列表,避免流状态后续被改动 workBookList.append((fileName, output.getvalue())) output.close()
zip打包函数:
def generate_zip(files): zip_buffer = BytesIO() # 新建空压缩包必须用"w"写入模式,禁止对空流用"a"追加模式 with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED, False) as zip_file: for fName, file_bytes in files: zip_file.writestr(fName, file_bytes) zip_buffer.seek(0) return zip_buffer.getvalue()
效果说明
- 每个Excel文件在生成瞬间就被转为独立的字节对象,完全不存在后续循环覆盖、流指针错位的问题
- 压缩包结构合法,所有写入的文件条目都能正常解析,不会出现部分文件丢失的情况
- 临时流资源及时释放,内存占用更稳定
内容的提问来源于stack exchange,提问作者jjulian91
相关产品推荐
相关产品推荐

