一、文件壓縮與解壓縮模塊 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}")