杰瑞科技汇

Python zipfile升级要注意哪些问题?

这里的“升级”可以从两个层面来理解:

  1. 使用现代的、更推荐的 API:从旧版本的 zipfile 中一些繁琐、易错的使用方式,升级到 Python 3.6+ 引入的更简洁、更强大的上下文管理器(with 语句)和 ZipFile.write() 的新用法。
  2. 处理更复杂的场景:升级到使用 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 模块支持两种主要的加密方式:

  1. 传统加密 (PKWARE 简单加密):不安全,容易被破解,仅用于兼容旧软件。
  2. 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 构造函数可以直接接受 compresslevelencryption 参数,使代码更清晰。

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

核心升级建议:

  1. 拥抱 with 语句:只要是处理文件、网络连接等资源,都优先使用 with 语句,这是现代 Python 编程的基石。
  2. 启用 ZIP64:如果你不确定文件大小,或者在处理任何可能较大的文件集合时,直接在创建 ZipFile 时设置 allowZip64=True,一劳永逸。
  3. 使用 AES 加密:如果需要加密,不要使用传统的 PKWARE 加密,直接选择 zipfile.ZIP_AES_256
  4. 考虑内存流:在需要高性能或避免临时文件的应用中(如 Web 服务),io.BytesIO 是你的好帮手。

通过以上这些“升级”,你可以让 zipfile 的代码更安全、更强大、更符合现代 Python 的编程范式。

分享:
扫描分享到社交APP
上一篇
下一篇