在日常工作和生活中,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 解压编码问题(比如中文文件名乱码)而头疼?或者你开发过“批量解压并重命名”的小工具?欢迎在评论区分享你的宝贵经验或踩坑经历,让我们一起让文件处理更加优雅。
1万+

被折叠的 条评论
为什么被折叠?



