Python标准库zipfile模块无法创建带密码的ZIP文件,仅支持读取传统ZipCrypto加密(Python 3.6+默认禁用);写入时setpassword()等方法无效,必须借助7z或zip等外部工具实现加密压缩。

zipfile 不支持写入密码保护的 ZIP 文件
Python 标准库 zipfile 模块**无法创建带密码的加密 ZIP 文件**——它只支持读取传统 ZIP 加密(即 ZipCrypto,已不安全),且从 Python 3.6 起默认禁用该功能;写入时完全不提供 setpassword() 或类似接口用于加密压缩。你调用 ZipFile.write() 时传任何密码参数都不会生效。
常见错误现象:
• 尝试用 pwd=b'123' 参数传给 ZipFile 构造函数写入时被忽略
• 用 zipfile.ZIP_DEFLATED + 密码参数仍生成无密码 ZIP
• 误以为 setpassword() 可用于写入(它仅在读取时设置解密密钥)
如果你需要生成带密码的 ZIP,必须借助外部工具:
• 7z a -p123 archive.zip file.txt(推荐,AES-256 安全)
• zip -P123 archive.zip file.txt(ZipCrypto,不推荐)
• 或用 subprocess 调用它们,而非依赖 zipfile
用 zipfile 读取密码保护 ZIP 中的特定文件
可以读取传统加密 ZIP(如用 zip -P 生成的),但需注意:Python 3.6+ 默认禁用 ZipCrypto 支持,需显式启用 zipfile.PyZipFile 不适用,要用 ZipFile 并手动处理密码。
立即学习“Python免费学习笔记(深入)”;
实操要点:
• 必须用 bytes 类型密码(如 b'123'),字符串会报 TypeError
• 密码需在调用 .read() 前通过 .setpassword() 设置,不是构造时传入
• 只能对单个文件内容解密读取,不能直接 .extractall()(会抛 RuntimeError: File is encrypted)
• 若 ZIP 含多个文件,每个 .read() 都要先 setpassword()(它不持久化)
示例:
with zipfile.ZipFile('secure.zip') as z:
z.setpassword(b'123')
content = z.read('data.txt') # 成功读取
高效提取 ZIP 中的某个文件而不解压全部内容
这是 zipfile 的典型优势场景——无需把整个 ZIP 拉到内存或写临时文件,直接定位并读取目标成员。
关键点:
• 用 z.namelist() 查看可用文件名,注意路径分隔符是 '/'(即使在 Windows 上)
• 用 z.getinfo(name) 获取元数据(大小、修改时间等),避免 .read() 前重复查找
• 直接 z.read(name) 是最简方式;若文件大,改用 z.open(name) 返回类文件对象流式读取
• 若目标文件不存在,.read() 抛 KeyError,建议先 if name in z.namelist(): 判断
示例(安全读取):
with zipfile.ZipFile('archive.zip') as z:
target = 'config.json'
if target in z.namelist():
data = z.read(target) # 或 z.open(target).read()
为什么 extract() 和 extractall() 在加密 ZIP 上失败
extract() 和 extractall() 内部调用的是底层 C 实现的解压逻辑,它不接受密码参数,也不触发 setpassword() 设置的密钥。它们的设计前提是 ZIP 未加密或已由其他方式解密(比如系统级挂载)。
所以:
• 即使你调过 z.setpassword(b'xxx'),再调 z.extract('a.txt') 仍会报 RuntimeError: File is encrypted
• 没有绕过方法——这是模块限制,不是用法问题
• 替代方案只有:先用 .read() 拿到字节,再手动写入文件;或改用 7z/unzip -P 命令行
真正容易被忽略的一点:ZipCrypto 加密的 ZIP,其文件头明文暴露文件名和大小,但内容加密。这意味着 namelist() 总能成功,而 read() 才真正触发解密——密码错就报 RuntimeError: Bad password for file,不是构造时报错。


















