zipfile,一个处理ZIP文件的 Python 库!

在日常工作和生活中,ZIP 压缩包无处不在——打包附件发送邮件、备份项目代码、批量下载多张照片、解压从网上下载的资料集。对于普通用户,通常使用 WinRAR、7‑Zip 等图形软件操作;但对于开发者,当我们需要自动批量压缩日志解压用户上传的压缩包从 ZIP 中读取特定文件而不解压全部、甚至创建加密的分卷压缩时,Python 的 zipfile 模块就成为了利器。例如,运维脚本每天自动将 /var/log 下旧的日志打包归档;数据爬虫将抓取的图片直接写入 ZIP 而不占用过多小文件句柄;办公自动化中批量解压几十个附件并提取关键表格。zipfile 让你在代码层面完美控制 ZIP 的压缩、读取、添加与修改。


一、安装库

zipfile 是 Python 标准库,无需额外安装。直接导入即可:

python

import zipfile

此外,处理密码时可能需要 pyzipper(第三方),但标准 zipfile 支持无密码或简单 ZipCrypto(不推荐用于强安全场景)。


二、基本用法

下面通过 4 个小步骤,掌握 zipfile 的核心操作。

1. 创建并写入 ZIP 文件

python

import zipfile

# 写入模式 'w':新建或覆盖
with zipfile.ZipFile('example.zip', 'w') as zf:
    zf.write('document.txt')          # 将文件加入压缩包
    zf.write('photos/photo1.jpg')     # 可以指定相对路径
    # 也可以写入字符串内容(不依赖磁盘文件)
    zf.writestr('readme.txt', '这是压缩包内的说明文本')

2. 读取 ZIP 文件内容

python

with zipfile.ZipFile('example.zip', 'r') as zf:
    # 列出所有文件名
    print(zf.namelist())
    # 读取特定文件的内容(文本模式需解码)
    content = zf.read('readme.txt').decode('utf-8')
    print(content)

3. 解压 ZIP 文件

python

# 解压全部到指定目录
with zipfile.ZipFile('example.zip', 'r') as zf:
    zf.extractall('output_folder/')

# 解压单个文件
with zipfile.ZipFile('example.zip', 'r') as zf:
    zf.extract('document.txt', 'output_folder/')

4. 追加文件到已有 ZIP

使用模式 'a'(append)可以在不重新压缩全部文件的前提下添加新文件。

python

with zipfile.ZipFile('example.zip', 'a') as zf:
    zf.write('new_file.csv')
    # 注意:无法删除或重命名已有条目(需要重建)

三、高级用法

1. 处理 ZIP 中的目录结构

write() 的第二个参数可指定归档内的路径别名:

python

with zipfile.ZipFile('archive.zip', 'w') as zf:
    zf.write('local_file.txt', 'subdir/renamed.txt')   # 归档内放于 subdir/ 下并改名
    zf.write('whole_folder/', arcname='backup')        # 将文件夹及其内容放入 backup/

2. 使用不同的压缩方式

默认是 ZIP_STORED(仅存储,不压缩),可改为 ZIP_DEFLATED(需要 zlib 库):

python

with zipfile.ZipFile('compressed.zip', 'w', compression=zipfile.ZIP_DEFLATED, compresslevel=6) as zf:
    zf.write('large_file.bin')

注:compresslevel 仅 Python 3.7+ 支持,且需 zlib。

3. 读取带密码的 ZIP(ZipCrypto)

python

# 标准库支持密码,但只能解密,不能加密(Python 3.6+)
with zipfile.ZipFile('protected.zip', 'r') as zf:
    zf.setpassword(b'secret')
    zf.extractall('output/')

对于更安全的 AES‑256 加密,请使用 pyzipper 库。

4. 检查 ZIP 文件完整性

python

with zipfile.ZipFile('example.zip', 'r') as zf:
    badfile = zf.testzip()   # 返回第一个损坏的文件名,若无损坏返回 None
    if badfile:
        print(f"损坏文件: {badfile}")
    else:
        print("所有文件完整")

5. 从 ZIP 中过滤读取(不遍历整个 ZIP)

python

def read_specific_file(zip_path, target_name):
    with zipfile.ZipFile(zip_path, 'r') as zf:
        if target_name in zf.namelist():
            return zf.read(target_name)
        return None

四、实际应用场景

场景1:批量压缩指定目录下所有文件(保留结构)

日常备份:将 data/ 下所有内容压缩并加上时间戳。

python

import zipfile
import os
from datetime import datetime

def backup_to_zip(folder_path, output_dir='.'):
    folder_name = os.path.basename(folder_path)
    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    zip_name = f"{folder_name}_backup_{timestamp}.zip"
    zip_path = os.path.join(output_dir, zip_name)
    
    with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zf:
        for root, dirs, files in os.walk(folder_path):
            for file in files:
                full_path = os.path.join(root, file)
                arcname = os.path.relpath(full_path, start=os.path.dirname(folder_path))
                zf.write(full_path, arcname)
    return zip_path

backup_to_zip('./my_project')

场景2:从多个 ZIP 中并行提取特定类型的文件(如所有 .xlsx)

假设你有一个目录,里面有很多 ZIP 压缩包,每个包内都散落着 Excel 报表。你需要把所有 .xlsx 文件提取到一个文件夹中。

python

import zipfile
import glob
import os

def extract_all_xlsx_from_zips(zip_dir, output_dir):
    os.makedirs(output_dir, exist_ok=True)
    for zip_path in glob.glob(os.path.join(zip_dir, '*.zip')):
        with zipfile.ZipFile(zip_path, 'r') as zf:
            for info in zf.infolist():
                if info.filename.endswith('.xlsx'):
                    # 避免重名
                    base = os.path.basename(info.filename)
                    dest = os.path.join(output_dir, base)
                    # 如果重名,加上来源 ZIP 前缀
                    if os.path.exists(dest):
                        prefix = os.path.splitext(os.path.basename(zip_path))[0]
                        dest = os.path.join(output_dir, f"{prefix}_{base}")
                    with zf.open(info) as src, open(dest, 'wb') as dst:
                        dst.write(src.read())
                    print(f"提取: {dest}")

extract_all_xlsx_from_zips('./zip_folder', './all_excels')

场景3:将内存中的多个数据流直接压缩为 ZIP(不落临时文件)

在 Web 应用中,用户点击“导出所有图片”时,后端内存中已有图片 bytes,可直接打包 ZIP 返回。

python

import zipfile
from io import BytesIO

def create_zip_from_bytes(files_dict):
    """
    files_dict: {filename: bytes_content}
    返回 BytesIO 对象,可直接用于 HTTP 响应
    """
    zip_buffer = BytesIO()
    with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zf:
        for filename, data in files_dict.items():
            zf.writestr(filename, data)
    zip_buffer.seek(0)
    return zip_buffer

# 模拟:三个图片 bytes
files = {
    'photo1.jpg': b'\xff\xd8...',   # 真实 JPEG 数据
    'data.csv': b'id,name\n1,Alice',
    'readme.txt': '这是一个导出包'.encode('utf-8')
}
zip_stream = create_zip_from_bytes(files)
# 然后返回 Flask 响应:send_file(zip_stream, attachment_filename='export.zip')

场景4:分卷 ZIP(跨卷)的处理

标准 zipfile 不支持创建分卷,但可以读取已存在的分卷(如 .z01, .z02, .zip)。对于创建分卷,通常使用命令行或第三方库。但我们可以实现一个简单的“切分”逻辑:先将目录压缩成一个大 ZIP,再手动分割文件(不推荐生产环境)。


五、结尾互动

总的来说,zipfile 是 Python 内置的压缩工具库,它足够满足 90% 的 ZIP 操作需求:创建、读取、提取、追加。在自动化运维、数据备份、批量文档处理、Web 导出等场景中,它能让你的代码摆脱对外部解压软件的依赖。唯一需要注意的地方是:标准库的加密只支持脆弱的 ZipCrypto,对于需要安全传输的场景,建议先用 pyzipper 或单独对文件进行加密(如 AES)。此外,处理超大 ZIP 时请使用流式读取,避免一次性加载整个 ZIP 到内存。

你在实际工作中是否遇到过因为 ZIP 解压编码问题(比如中文文件名乱码)而头疼?或者你开发过“批量解压并重命名”的小工具?欢迎在评论区分享你的宝贵经验或踩坑经历,让我们一起让文件处理更加优雅。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值