zipfile.ZipFile()写入必须用'w'或'a'模式,'r'不支持写入;'a'仅对已存在ZIP追加,否则等效'w';需调用close()或with语句;路径须用relpath+arcname转相对路径;中文名需注意编码兼容性;大文件会内存暴涨。

zipfile.ZipFile() 写入模式选错导致压缩包为空
用 zipfile.ZipFile() 创建 ZIP 文件时,'w' 和 'a' 模式行为差异很大:选 'w' 会清空已有文件并重建;选 'a' 才能追加,但若目标不存在,它也会新建——看似一样,实则底层逻辑不同。更关键的是,如果误用 'r' 模式打开再写,直接抛 ValueError: ZIP does not support writing mode 'r'。
- 写新包一律用
'w',哪怕只是加一个文件 - 想往已有 ZIP 里追加?Python 标准库不支持原地追加 ——
'a'只在文件完全不存在时等效于'w',存在时才真追加;但一旦 ZIP 已有内容,'a'会尝试读取目录结构,若损坏或非标准格式就失败 - 务必调用
.close()或用with语句,否则文件句柄未释放,压缩包可能写入不全、体积为 0
os.walk() 遍历路径传给 write() 时路径错乱
常见错误是把 os.walk() 返回的 root + filename 直接喂给 ZipFile.write(),结果压缩包里出现完整绝对路径(如 /home/user/docs/report.txt),解压后层层嵌套。ZIP 规范要求内部路径是相对的,write() 默认保留传入路径的层级。
- 用
arcname参数重写归档内路径:zf.write(full_path, arcname=rel_path) - 计算
rel_path推荐用os.path.relpath(full_path, start=base_dir),其中base_dir是你希望压缩包根目录对应的实际路径 - 别依赖
os.path.basename()拼接 —— 它只取最后一级,丢失中间目录结构 - 注意 Windows 路径分隔符:传入
arcname时统一用/(ZIP 标准),zipfile内部会处理兼容性
中文文件名乱码或解压失败
ZIP 本身没强制规定编码,Windows 默认用 GBK,macOS/Linux 默认 UTF-8。Python 3 的 zipfile 在读写时默认按 UTF-8 解析文件名,但老压缩包可能是 GBK 编码,直接 namelist() 就返回乱码,extractall() 则可能抛 UnicodeDecodeError。
- 读取未知来源 ZIP 时,先试
ZipFile.namelist();若报错或内容异常,改用ZipFile.filelist获取原始ZipInfo对象,手动 decode:info.filename.encode('cp437').decode('gbk') - 写入含中文路径的文件,确保源字符串是 Unicode(Python 3 默认),
zipfile会自动 UTF-8 编码写入 —— 但 Windows 资源管理器可能不认,需额外兼容 - 跨平台分发 ZIP?优先用
shutil.make_archive(),它内部对中文更鲁棒;或用第三方库如pyminizip显式指定编码
大文件压缩内存暴涨或卡死
ZipFile.write() 默认把整个文件读进内存再压缩,遇到几百 MB 的日志或视频,Python 进程 RSS 瞬间翻倍,还可能触发系统 OOM Killer。这不是 bug,是设计使然 —— 它没流式写入接口。
立即学习“Python免费学习笔记(深入)”;
- 小文件(write() 没问题
- 大文件必须分块读写:用
ZipFile.writestr()+ 自己控制zlib.compress()流,但要手算 ZIP 头和校验和,极不推荐 - 务实方案是绕过
zipfile:调用系统命令subprocess.run(['zip', '-r', 'out.zip', 'dir/']),或用shutil.make_archive()(底层调用系统 zip 或纯 Python 实现,取决于平台) - 注意
shutil.make_archive()的format='zip'在某些旧版 Python 中不支持arcname定制,需确认版本 ≥3.7
真正麻烦的不是语法,是 ZIP 规范和操作系统实现之间的缝隙——比如 macOS 的 Archive Utility 对 ZIP64 支持不全,而 Python 默认超过 2GB 就切 ZIP64;又比如有些嵌入式设备解压器只认传统 ZIP,不认数据描述符。这些边界情况,光看文档根本踩不到,得靠实际压一压、解一解才知道。


















