这里的“升级”可以从两个层面来理解:
- 使用现代的、更推荐的 API:从旧版本的
zipfile中一些繁琐、易错的使用方式,升级到 Python 3.6+ 引入的更简洁、更强大的上下文管理器(with语句)和ZipFile.write()的新用法。 - 处理更复杂的场景:升级到使用
zipfile的高级功能,比如处理 ZIP64 格式(用于处理大于 4GB 的文件)、加密 ZIP 文件、流式处理等。
下面我将从这两个层面,结合代码示例,为你详细讲解如何“升级”你的 zipfile 使用方式。
使用现代 API (从旧到新)
在 Python 3.6 之前,操作 zipfile 通常比较繁琐,尤其是在写入文件时,Python 3.6+ 对 ZipFile 进行了重要改进,引入了 ZipFile 作为上下文管理器,并简化了 write() 方法。
场景 1:创建和写入 ZIP 文件
❌ 旧方式 (Python 3.6 之前)
这种方式需要手动关闭 ZipFile 对象,如果中间发生异常,可能导致文件未正确关闭或损坏。
import zipfile
# 1. 创建一个新的 ZIP 文件
zip_file = zipfile.ZipFile('my_archive.zip', 'w', zipfile.ZIP_DEFLATED)
# 2. 添加单个文件
zip_file.write('file1.txt', arcname='data/file1.txt')
# 3. 添加一个文件夹下的所有文件
import os
for root, dirs, files in os.walk('my_folder'):
for file in files:
file_path = os.path.join(root, file)
# 计算在 ZIP 中的相对路径
arcname = os.path.relpath(file_path, 'my_folder')
zip_file.write(file_path, arcname=arcname)
# 4. 必须手动关闭
zip_file.close()
✅ 新方式 (Python 3.6+ 推荐)
使用 with 语句(上下文管理器),可以确保 ZipFile 对象在代码块执行完毕后(即使发生异常)被自动关闭,代码更安全、更简洁。
import zipfile
import os
# 使用 with 语句,自动管理资源
with zipfile.ZipFile('my_archive_new.zip', 'w', zipfile.ZIP_DEFLATED) as zipf:
# 添加单个文件
zipf.write('file1.txt', arcname='data/file1.txt')
# 添加一个文件夹下的所有文件
for root, dirs, files in os.walk('my_folder'):
for file in files:
file_path = os.path.join(root, file)
arcname = os.path.relpath(file_path, 'my_folder')
zipf.write(file_path, arcname=arcname)
# with 代码块结束,zipf 自动关闭
场景 2:读取 ZIP 文件
❌ 旧方式
同样,需要手动关闭。
zip_file = zipfile.ZipFile('my_archive.zip', 'r')
file_list = zip_file.namelist() # 获取文件列表
print(file_list)
# 读取特定文件
with zip_file.open('file1.txt') as member_file:
print(member_file.read().decode('utf-8'))
zip_file.close()
✅ 新方式
with zipfile.ZipFile('my_archive.zip', 'r') as zipf:
file_list = zipf.namelist()
print("文件列表:", file_list)
# 读取特定文件
with zipf.open('file1.txt') as member_file:
print("文件内容:", member_file.read().decode('utf-8'))
# zipf 自动关闭
处理更复杂的场景 (功能升级)
当你的需求超越了简单的打包和解包时,就需要用到 zipfile 的高级功能。
场景 3:处理大文件 (ZIP64 格式)
标准的 ZIP 格式有 4GB 的限制(文件大小和 ZIP 文件总大小),当要打包的文件超过这个限制时,就需要启用 ZIP64 扩展。
✅ 升级方法
在创建 ZipFile 时,将 allowZip64 参数设置为 True (默认就是 True,但显式写出可以明确意图)。
import zipfile
# 假设我们有一个非常大的文件 (5GB)
large_file_path = 'very_large_file.dat'
archive_name = 'large_archive.zip'
# allowZip64=True 会自动处理大文件
with zipfile.ZipFile(archive_name, 'w', allowZip64=True) as zf:
zf.write(large_file_path, arcname='data/very_large_file.dat')
print(f"已创建大文件归档: {archive_name}")
场景 4:创建加密的 ZIP 文件
zipfile 模块支持两种主要的加密方式:
- 传统加密 (PKWARE 简单加密):不安全,容易被破解,仅用于兼容旧软件。
- WinZip AES 加密:更安全,支持 128-bit 和 256-bit 密钥。这是目前推荐的方式。
❌ 旧方式 (传统加密)
# 传统加密,不安全!仅用于兼容性
with zipfile.ZipFile('encrypted_traditional.zip', 'w', compression=zipfile.ZIP_STORED, encryption=zipfile.ZIP_ENTRY) as zf:
zf.setpassword(b'weakpassword')
zf.write('file1.txt')
✅ 新方式 (推荐使用 WinZip AES 加密)
从 Python 3.7 开始,ZipFile 构造函数可以直接接受 compresslevel 和 encryption 参数,使代码更清晰。
import zipfile
# 推荐使用 AES 加密
# encryption=zipfile.ZIP_AES_256 表示使用 256-bit AES 加密
# compresslevel=6 是一个平衡值,速度和压缩率都不错
with zipfile.ZipFile('encrypted_aes.zip', 'w', compression=zipfile.ZIP_DEFLATED, compresslevel=6, encryption=zipfile.ZIP_AES_256) as zf:
# 密码必须是 bytes 类型
zf.setpassword(b'a-very-strong-password-123')
zf.write('file1.txt', arcname='secret_file.txt')
print("已创建 AES 加密的 ZIP 文件。")
场景 5:从内存中创建 ZIP 文件 (流式处理)
有时你不想先将文件写入磁盘,而是想直接在内存中生成 ZIP 文件,例如用于 Web API 的响应。
✅ 升级方法
使用 io.BytesIO 作为内存中的文件流。
import zipfile
import io
# 假设这是我们从数据库或网络获取的二进制数据
file_content = b"Hello from memory! This is a test file."
file_name_in_zip = "greeting.txt"
# 1. 创建一个内存中的二进制流
memory_file = io.BytesIO()
# 2. 将这个流作为 'filename' 传递给 ZipFile
with zipfile.ZipFile(memory_file, 'w', zipfile.ZIP_DEFLATED) as zf:
zf.writestr(file_name_in_zip, file_content)
# 3. memory_file 中已经包含了完整的 ZIP 数据可以发送给客户端或写入磁盘
zip_data = memory_file.getvalue()
# 示例:将内存中的 ZIP 写入磁盘文件
with open('from_memory.zip', 'wb') as f:
f.write(zip_data)
print("已从内存创建 ZIP 文件并保存为 from_memory.zip")
总结与最佳实践
| 场景 | 旧/不推荐方式 | 新/推荐方式 | 关键升级点 |
|---|---|---|---|
| 基本操作 | 手动 open() 和 close() |
使用 with 语句 |
安全、简洁、资源自动管理 |
| 写入文件 | zipf.write(path, arcname) |
zipf.write(path, arcname) |
配合 with 使用,代码更健壮 |
| 处理大文件 | 可能失败或报错 | 在 ZipFile 中设置 allowZip64=True |
突破 4GB 限制 |
| 文件加密 | encryption=zipfile.ZIP_ENTRY (不安全) |
encryption=zipfile.ZIP_AES_256 |
更安全、更现代的加密标准 |
| 内存操作 | 先写磁盘再读入 | 使用 io.BytesIO 作为 ZipFile 的文件流 |
高效、无需磁盘 I/O |
核心升级建议:
- 拥抱
with语句:只要是处理文件、网络连接等资源,都优先使用with语句,这是现代 Python 编程的基石。 - 启用 ZIP64:如果你不确定文件大小,或者在处理任何可能较大的文件集合时,直接在创建
ZipFile时设置allowZip64=True,一劳永逸。 - 使用 AES 加密:如果需要加密,不要使用传统的 PKWARE 加密,直接选择
zipfile.ZIP_AES_256。 - 考虑内存流:在需要高性能或避免临时文件的应用中(如 Web 服务),
io.BytesIO是你的好帮手。
通过以上这些“升级”,你可以让 zipfile 的代码更安全、更强大、更符合现代 Python 的编程范式。
