使用 Python 解压缩 zip 文件
使用 Python 解压缩 zip 文件
压缩
压缩文件时,可以将压缩文件保存在本地或保存在内存中,将压缩文件保存在内存中时,方便后续使用,比如直接返回给前端,也就不用再执行删除操作。
import zipfile from pathlib import Path from io import BytesIO def zip_to_file(): """压缩文件保存到文件中""" zip_file = Path('./test.zip') with zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED) as zip_obj: # 将字符串写入文件压缩 zip_obj.writestr('test.txt', 'test file') # 压缩本地文件 f = Path('./test.json') if f.exists(): zip_obj.write(f, 'test.json') def zip_to_mem(): """压缩文件保存到内存中""" with BytesIO() as bio, zipfile.ZipFile(bio, 'w', zipfile.ZIP_DEFLATED) as zip_obj: # 使用 BytesIO 接收压缩文件 # 将字符串写入文件压缩 zip_obj.writestr('test.txt', 'test file') # 压缩本地文件 f = Path('./test.json') if f.exists(): zip_obj.write(f, 'test.json') # 保存数据时,需要先手动 close,否则最后写入的文件会缺少一部分数据 zip_obj.close() # 将内存中的数据保存到文件中方便展示效果,实际中可以直接发送给前端或其他处理 with open('test.zip', 'wb') as fw: fw.write(bio.getvalue()) if __name__ == '__main__': zip_to_mem()
问题
当把压缩文件保存在 BytesIO 中时,按照以下方式保存时,使用 zipfile 去解压压缩文件,报错zipfile.BadZipFile: File is not a zip file
,但用其他压缩软件可以正常解压。
with BytesIO() as bio, zipfile.ZipFile(bio, 'w', zipfile.ZIP_DEFLATED) as zip_obj: # 使用 BytesIO 接收压缩文件 # 将字符串写入文件压缩 zip_obj.writestr('test.txt', 'test file') # 压缩本地文件 f = Path('./test.json') if f.exists(): zip_obj.write(f, 'test.json') # 将内存中的数据保存到文件中方便展示效果,实际中可以直接发送给前端或其他处理 with open('test.zip', 'wb') as fw: fw.write(bio.getvalue())
检查 bio 中数据后,发现在 ZipFile 对象close
方法中还会调用_write_end_record
写入数据,而使用上面的保存方式时,在写入本地文件时,ZipFile 对象还没有调用close
方法,导致最后写入的数据缺少一部分,因此在写入本地文件前,手动调用close
方法。
异常数据:b'PK\x03\x04\x14\x00\x00\x00\x08\x00\x95\x8d[W\xc1kd\xf2\x0b\x00\x00\x00\t\x00\x00\x00\x08\x00\x00\x00test.txt+I-.QH\xcb\xccI\x05\x00'
正常数据:b'PK\x03\x04\x14\x00\x00\x00\x08\x00\x95\x8d[W\xc1kd\xf2\x0b\x00\x00\x00\t\x00\x00\x00\x08\x00\x00\x00test.txt+I-.QH\xcb\xccI\x05\x00PK\x01\x02\x14\x00\x14\x00\x00\x00\x08\x00\x95\x8d[W\xc1kd\xf2\x0b\x00\x00\x00\t\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00test.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00\x00\x001\x00\x00\x00\x00\x00'
解压
可以读取本地压缩文件或内存中压缩文件,然后解压到本地目录或内存中
import json import zipfile from pathlib import Path def unzip_to_file(): """压缩到文件中""" zip_file = Path('./test.zip') with zipfile.ZipFile(zip_file, 'r') as zip_obj: # 直接解压在当前目录 zip_obj.extractall() def unzip_to_mem(): """解压到内存中""" zip_file = Path('./test.zip') with zipfile.ZipFile(zip_file, 'r') as zip_obj: # 循环压缩包中的所有文件 for file_info in zip_obj.filelist: # 预防压缩炸弹,限制解压文件大小 if file_info.file_size > 1024 * 1024 * 2: print(f'{file_info.filename} 文件大小异常') break if file_info.filename == 'test.txt': # 读取文件打印文件数据 print(zip_obj.open(file_info).read()) def unzip_from_to_mem(): """解压到内存中""" zip_file = Path('./test.zip') # 示例为了演示,先使用 open 打开文件,再传入 ZipFile,实际中,数据可能来自于前端上传等 with open(zip_file, 'rb') as f, zipfile.ZipFile(f, 'r') as zip_obj: # 循环压缩包中的所有文件 for file_info in zip_obj.filelist: # 预防压缩炸弹,限制解压文件大小 if file_info.file_size > 1024 * 1024 * 2: print(f'{file_info.filename} 文件大小异常') continue if file_info.filename == 'test.json': # 读取文件打印文件数据 print(json.loads(zip_obj.open(file_info).read())) if __name__ == '__main__': unzip_from_to_mem()
PS
- 在读取内存中压缩文件时,示例是使用 open 打开文件,仅作为示例,实际中,应该是前端上传数据或其他方式
- 当使用 Flask 接收上传的压缩文件时,如果后面会多次使用该数据,需要先将数据读取出来方便后续使用
bytes_io = BytesIO(request.files.get('file').stream.read())
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)