Python3 中使用zipfile进行文件(夹)的压缩、解压缩
一、文件压缩与解压缩模块 zipfile简介
zipfile
是 Python 标准库中用于处理 ZIP 压缩文件的模块,提供了创建、读取、写入、解压 ZIP 文件的完整功能。它支持多种压缩算法,无需安装额外依赖,是处理 ZIP 格式的首选工具。
核心功能与常用类
zipfile.ZipFile
类
这是模块的核心类,用于创建和操作 ZIP 文件,常用参数:file
:ZIP 文件路径或文件对象mode
:操作模式('r'
读取、'w'
创建、'a'
追加)compression
:压缩算法(ZIP_STORED
无压缩,ZIP_DEFLATED
常用压缩)
常用操作示例
1. 读取 ZIP 文件内容
import zipfilewith zipfile.ZipFile('example.zip', 'r') as zf:# 查看压缩包内所有文件print(zf.namelist()) # 返回文件名列表# 查看文件信息(大小、压缩率等)for info in zf.infolist():print(f"文件名: {info.filename}, 原始大小: {info.file_size}, 压缩后: {info.compress_size}")
2. 解压 ZIP 文件
import zipfilewith zipfile.ZipFile('example.zip', 'r') as zf:# 解压所有文件到指定目录(默认当前目录)zf.extractall(path='解压目录')# 解压单个文件zf.extract('文件路径/文件名.txt', path='单个文件解压目录')
3. 创建 ZIP 文件(压缩文件/文件夹)
import zipfile
import os# 压缩单个文件
with zipfile.ZipFile('output.zip', 'w', zipfile.ZIP_DEFLATED) as zf:zf.write('file1.txt', arcname='file1.txt') # arcname 可指定压缩包内文件名# 压缩文件夹(含子目录)
def zip_folder(folder_path, zip_path):with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zf:for root, dirs, files in os.walk(folder_path):for file in files:file_path = os.path.join(root, file)# 保持相对路径,确保文件夹结构arcname = os.path.relpath(file_path, os.path.dirname(folder_path))zf.write(file_path, arcname=arcname)zip_folder('需要压缩的文件夹', 'result.zip')
4. 向现有 ZIP 追加文件
import zipfilewith zipfile.ZipFile('existing.zip', 'a', zipfile.ZIP_DEFLATED) as zf:zf.write('new_file.txt') # 追加新文件到已有压缩包
注意事项
- 压缩算法:
ZIP_DEFLATED
需要系统支持 zlib 库(通常默认支持),否则需使用无压缩的ZIP_STORED
。 - 路径处理:压缩文件夹时需通过
arcname
控制路径,避免生成冗余的绝对路径。 - 大型文件:处理大文件时建议使用
with
语句,确保资源正确释放。
通过 zipfile
模块,可轻松实现 ZIP 文件的全流程管理,满足日常压缩/解压需求。
二、案例实操
2.0 测试文件准备
原始结构为:
dir_level_1/
├── file1.txt
├── subfolder1/
│ └── file2.txt
└── subfolder2/└── subsubfolder/└── file3.txt
程序设计初衷:
将目录“dir_level_1”下所有的文件、子文件夹、子文件夹下的文件,安装原先的层次结构,压缩为一个文件“dir_level_1.zip”。
2.1 综合案例:实现文件压缩、查看压缩内容、解压
"""14-5 文件压缩与解压模块-zipFile操作系统提供将一般文件或目录进行压缩的功能,压缩后的扩展名是zip,Python有 zipFile 模块也可以将文件或目录压缩以及解压缩。压缩文件或目录:zipfile.ZipFile(file_name, mode='w', compression=ZIP_DEFLATED)file_name: 压缩文件的名称mode: 压缩文件的模式,w表示写入,a表示追加compression: 压缩算法,ZIP_DEFLATED表示使用 deflate 算法进行压缩解压文件或目录:zipfile.ZipFile(file_name, mode='r')14-5-1 执行文件或目录的压缩说明:执行文件压缩前首先要使用ZipFile()方法创建一个压缩后的文件对象,在这个方法中另外要加上“w”参数,表明未来是提供 write() 方法写入文件。语法:fileZip = zipfile.ZipFile('out.zip', mode='w',compression=ZIP_DEFLATED)上述fileZip和out.zip皆可以自由命名,fileZip是压缩文件对象,代表的out.zip,未来将被压缩的文件数据写入到此对象中,就可以将结果保存为 out.zip 文件了。注意:1、虽然ZipFile()无法执行整个目录的压缩,不过可以使用循环(递归)方式将目录底下的文件或文件夹进行压缩,即可达到压缩整个目录的目的。详见:c14-5.2_zip_with_hierarchy.py14-5-2 读取zip文件说明:1、listZipInfo.namelist() : 返回zip文件中所有文件的名称列表(List)。2、listZipInfo.infolist() : 返回各个元素的属性,如文件名、文件大小、压缩结果大小、文件时间、文件CRC码等。语法:listZipInfo = zipfile.ZipFile('dir_level_1.zip', 'r')print(listZipInfo.namelist()) # 获取文件(夹)列表print('\n')for fileInfo in listZipInfo.infolist():print(fileInfo.filename,'\t', fileInfo.file_size,'\t', fileInfo.compress_size)14-5-3 解压缩zip文件说明:1、zipfile.extractall() : 解压缩zip文件。2、zipfile.extract(fileName) : 解压缩指定文件。3、zipfile.extractall(path) : 解压缩zip文件到指定目录。语法:listZipInfo = zipfile.ZipFile('dir_level_1.zip', 'r')listZipInfo.extractall() # 解压所有文件listZipInfo.extract('dir_level_1.zip') # 解压指定文件listZipInfo.close()"""print("----------------------- 案例-14-5-1 执行文件或目录的压缩 -----------------------")
# ch14_41.py : 将当前工作目录下的 dir_level_1 目录压缩,压缩结果存储在 dir_level_1.zip 文件中.
"""
代码说明:这行代码的作用是遍历dir_level_1目录下的所有文件和目录(但不包括子目录中的内容)。具体解释如下:glob.glob('dir_level_1/*'):glob是一个用于匹配文件路径的模块,支持Unix shell-style的通配符
dir_level_1/*表示匹配dir_level_1目录下的所有文件和目录(一级内容)
这个表达式会返回一个包含所有匹配路径的列表
for name in ...:遍历glob返回的每个文件/目录路径
根据对项目文件结构的查看,dir_level_1目录包含以下内容:- 多个文件:2.docx、out14_27.txt等- 一个子目录:dir_level_2(包含1.docx和1.txt)需要注意的是,dir_level_1/*这种模式只会匹配dir_level_1目录下的直接内容,不会递归匹配子目录中的文件。所以在示例中,它会匹配到2.docx、out14_27.txt等文件以及 dir_level_2目录本身,但不会匹配dir_level_2 目录中的1.docx和1.txt。在代码中,这些匹配到的文件和目录会被逐一添加到dir_level_1.zip压缩文件中。
"""
import zipfile
import glob, osfileZip = zipfile.ZipFile('dir_level_1.zip', 'w')
for name in glob.glob('dir_level_1/*'): # 遍历指定目录下的所有文件,但测试下来,仅会压缩dir_level_1下首层文件及文件夹,而不会将二层dir_level_1\dir_level_2下的文件(如1.txt,1.docx)压缩进dir_level_1.zip中fileZip.write(name, os.path.basename(name), zipfile.ZIP_DEFLATED) # 参数3为压缩方式fileZip.close()print("----------------------- 案例-14-5-2 读取zip文件 -----------------------")
# ch14_41.py :
import zipfilelistZipInfo = zipfile.ZipFile('dir_level_1.zip', 'r')
print(listZipInfo.namelist()) # 获取文件(夹)列表
print('\n')
for fileInfo in listZipInfo.infolist():print(fileInfo.filename,'\t', fileInfo.file_size,'\t', fileInfo.compress_size, '\t', fileInfo.date_time, '\t', fileInfo.CRC)
'''
['2.docx', 'out14_27.txt', 'out14_28.txt', 'out14_29.txt', 'out14_30.txt', 'out14_31.txt', 'out41_V3.zip', 'dir_level_2/']2.docx 10240 9080 (2025, 8, 3, 1, 4, 52) 1145032402
out14_27.txt 13 15 (2025, 8, 2, 18, 23, 8) 2445962250
out14_28.txt 3 5 (2025, 8, 2, 18, 23, 8) 595022058
out14_29.txt 47 34 (2025, 8, 2, 18, 23, 8) 1873662565
out14_30.txt 51 36 (2025, 8, 2, 18, 23, 8) 24013343
out14_31.txt 101 42 (2025, 8, 2, 18, 23, 8) 676495025
out41_V3.zip 97041 71141 (2025, 8, 3, 9, 40, 58) 2754552733
dir_level_2/ 0 0 (2025, 8, 3, 0, 59, 16) 0
'''print("----------------------- 案例-14-5-3 解压缩zip文件 -----------------------")
# ch14_43.py : 将程序实例 ch14_41.py 所建立的 dir_level_1.zip 解压缩,同时将解压结果存入 out43 目录
import zipfilefileUnZip = zipfile.ZipFile("dir_level_1.zip", "r")
fileUnZip.extractall("out43")
fileUnZip.close()
2.2 压缩方法优化-V1版本
上一版压缩方法的缺陷
:
代码中:
fileZip = zipfile.ZipFile('dir_level_1.zip', 'w')
for name in glob.glob('dir_level_1/*'): fileZip.write(name, os.path.basename(name), zipfile.ZIP_DEFLATED)
这里的fileZip对象无法将文件夹下dir_level_1下文件夹dir_level_2中的文件1.docx压缩进来,而只会将dir_level_2文件夹本身压缩进来,未达到程序实现功能的初衷。
改进说明
:
要解决级联压缩文件夹(包含子文件夹结构)的问题,需要递归遍历文件夹中的所有文件,并保持原有的目录结构。
代码解释
要解决级联压缩文件夹(包含子文件夹结构)的问题,需要递归遍历文件夹中的所有文件,并保持原有的目录结构。以下是实现这一功能的完整代码:
代码清单
:
zip_recursive.py
import zipfile
import osdef zip_directory(folder_path, zip_file):"""递归压缩文件夹及其子目录中的所有文件参数:folder_path (str): 要压缩的文件夹路径zip_file (zipfile.ZipFile): 已打开的ZipFile对象"""# 遍历文件夹中的所有内容for item in os.listdir(folder_path):item_path = os.path.join(folder_path, item)# 如果是文件,直接添加到压缩包if os.path.isfile(item_path):# 计算相对路径,保持目录结构arcname = os.path.relpath(item_path, os.path.dirname(folder_path))zip_file.write(item_path, arcname=arcname)print(f"已添加文件: {arcname}")# 如果是文件夹,递归处理elif os.path.isdir(item_path):zip_directory(item_path, zip_file)# 使用示例
if __name__ == "__main__":# 要压缩的根文件夹路径root_folder = "dir_level_1"# 压缩文件保存路径zip_path = "dir_level_1.zip"# 创建并打开zip文件with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:zip_directory(root_folder, zipf)print(f"压缩完成,文件保存为: {zip_path}")
代码解析:
-
核心函数:
zip_directory
函数通过递归方式处理文件夹及其子文件夹- 对于文件:直接添加到压缩包,并通过
arcname
参数保持相对路径 - 对于子文件夹:递归调用自身处理
- 对于文件:直接添加到压缩包,并通过
-
关键技术点:
- 使用
os.path.relpath
计算文件相对路径,确保压缩包内保持原有的目录结构 - 使用
with
语句管理 ZipFile 对象,确保资源正确释放 - 使用
ZIP_DEFLATED
模式创建压缩的zip文件(而不是仅存储)
- 使用
-
使用方法:
- 将
root_folder
设置为根文件夹路径(如 “dir_level_1”) - 运行程序后,会将 dir_level_1 下所有文件、子目录(包括 dir_level_2 中的 1.docx)完整压缩到 dir_level_1.zip 中
- 将
这样处理后,压缩包内会完整保留原有的文件夹层次结构,而不是仅压缩最内层的文件夹。
2.3 压缩方法优化-V2版本
V1版缺陷
:
这样实现不能忠实的反馈原文件夹结构,本意是希望原先dir_level_1下的文件夹和文件都压缩至dir_level_1目录下,而目前的代码实现的逻辑是dir_level_1下的文件是放在了dir_level_1下,但dir_level_1下的文件夹,如 dir_level_2 却没有放在dir_level_1下,而是与dir_level_1平级了。
改进说明
:
要解决文件夹结构忠实还原的问题,关键在于正确设置压缩包内的相对路径。以下是改进后的代码,确保所有文件和子文件夹都正确嵌套在根目录下。
-
核心改进点:
- 明确将根文件夹名称(
root_basename
)作为压缩包内的顶级目录 - 所有文件和子文件夹都通过
os.path.join(root_basename, ...)
构建路径,确保嵌套在根目录下 - 使用
zip_subdirectory
专门处理子文件夹,保持完整的层级关系
- 明确将根文件夹名称(
-
结构保证:
假设原始结构为:dir_level_1/ ├── file1.txt ├── subfolder1/ │ └── file2.txt └── subfolder2/└── subsubfolder/└── file3.txt
压缩后在zip文件中会保持完全相同的结构:
dir_level_1/ ├── file1.txt ├── subfolder1/ │ └── file2.txt └── subfolder2/└── subsubfolder/└── file3.txt
-
使用方法:
- 将
root_folder
设置为根目录(如 “dir_level_1”) - 运行程序后,所有内容都会被正确压缩到该根目录下,不会出现平级问题
- 将
这种实现方式能精确还原原始文件夹的层级结构,确保子文件夹都正确嵌套在指定的根目录下。
代码清单
:
zip_with_hierarchy.py
import zipfile
import osdef zip_directory(root_folder, zip_file):"""递归压缩指定文件夹,保持完整的目录结构参数:root_folder (str): 要压缩的根文件夹路径zip_file (zipfile.ZipFile): 已打开的ZipFile对象"""# 获取根文件夹的基本名称,作为压缩包内的顶级目录root_basename = os.path.basename(root_folder)# 遍历根文件夹中的所有内容for item in os.listdir(root_folder):item_path = os.path.join(root_folder, item)# 构建压缩包内的相对路径,确保所有内容都在根文件夹名下arcname = os.path.join(root_basename, item)if os.path.isfile(item_path):# 添加文件,使用构建的相对路径zip_file.write(item_path, arcname=arcname)print(f"已添加文件: {arcname}")elif os.path.isdir(item_path):# 递归处理子文件夹,同时保持目录结构zip_subdirectory(item_path, zip_file, root_basename)def zip_subdirectory(subfolder_path, zip_file, root_basename):"""递归处理子文件夹,保持相对路径结构"""# 获取当前子文件夹相对于根文件夹的路径rel_path = os.path.relpath(subfolder_path, os.path.dirname(subfolder_path))# 构建压缩包内的完整路径base_arcname = os.path.join(root_basename, rel_path)for item in os.listdir(subfolder_path):item_path = os.path.join(subfolder_path, item)arcname = os.path.join(base_arcname, item)if os.path.isfile(item_path):zip_file.write(item_path, arcname=arcname)print(f"已添加文件: {arcname}")elif os.path.isdir(item_path):# 递归处理更深层次的子文件夹zip_subdirectory(item_path, zip_file, root_basename)# 使用示例
if __name__ == "__main__":# 要压缩的根文件夹路径root_folder = "dir_level_1"# 压缩文件保存路径zip_path = "dir_level_1.zip"# 确保根文件夹存在if not os.path.isdir(root_folder):print(f"错误: 文件夹 '{root_folder}' 不存在")else:# 创建并打开zip文件,使用DEFLATED模式进行压缩with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:zip_directory(root_folder, zipf)print(f"压缩完成,文件保存为: {zip_path}")