這裡介紹如何在 Python 中讀取與寫入各種格式的壓縮檔,包含 gzip、bz2、zip、tar 格式。
Python 本身就有支援各種壓縮檔案格式的模組,我們可以透過這些模組來讀取或寫入壓縮檔,常見的 gzip、bz2、zip、tar 格式都有支援,使用上非常方便。以下是各種壓縮格式的壓縮與解壓縮教學,還有一些範例程式碼。
gzip
Python 的 gzip
模組提供了用來處理 gzip 壓縮檔案的操作介面,而其內部是使用 zlib
模組來進行資料的壓縮與解壓縮。
讀取 gzip 壓縮檔
若要讀取 gzip 壓縮檔,最簡單的方式就是使用 gzip.open
:
import gzip with gzip.open('file.txt.gz', 'rb') as f: file_content = f.read()
寫入 gzip 壓縮檔
若要寫入 gzip 壓縮檔,同樣是使用 gzip.open
:
import gzip content = "Hello, gzip." with gzip.open('file.txt.gz', 'wb') as f: f.write(content)
以 gzip 壓縮檔案
若要以 gzip 格式壓縮一個普通檔案,可以使用 gzip
配合 shutil
模組:
import gzip import shutil with open('file.txt', 'rb') as f_in, gzip.open('file.txt.gz', 'wb') as f_out: shutil.copyfileobj(f_in, f_out)
這樣就會把 file.txt
經過 gzip 壓縮之後,儲存為 file.txt.gz
。
bzip2
Python 的 bz2
模組可以用來處理 bzip2 格式的壓縮與解壓縮。
讀取 bzip2 壓縮檔
若要讀取 bzip2 的壓縮檔,可以使用 bz2.BZ2File
:
import bz2 with bz2.BZ2File('file.txt.bz2', 'r') as f: file_content = f.read()
這樣就會把 file.txt.bz2
的檔案內容解壓縮之後,放在 file_content
變數中。
寫入 bzip2 壓縮檔
若要家資料寫入 bzip2 的壓縮檔,同樣是使用 bz2.BZ2File
:
import bz2 content = "Hello, bzip2." with bz2.BZ2File('file.txt.bz2', 'w') as f: f.write(content)
這樣就會將 content
中的資料以 bzip2 格式壓縮之後,寫入 file.txt.bz2
中。
以 bzip2 壓縮資料
若要在程式中直接壓縮或解壓縮 bzip2 格式的資料,可以使用 bz2.compress
與 bz2.decompress
這兩個函數:
# -*- coding: utf-8 -*- import bz2 import binascii original_data = 'Hello, bzip2.' print '原始的資料: ', len(original_data), original_data # 以 bzip2 壓縮資料 compressed = bz2.compress(original_data) print '壓縮後的資料: ', len(compressed), binascii.hexlify(compressed) # 解壓縮 bzip2 資料 decompressed = bz2.decompress(compressed) print '解壓縮後的資料:', len(decompressed), decompressed
原始的資料: 13 Hello, bzip2. 壓縮後的資料: 55 425a68393141592653595352837c0000021d804005100000401224c0102000310340d02001a68c27aaac8284f8bb9229c284829a941be0 解壓縮後的資料: 13 Hello, bzip2.
這裡的原始資料太小了,經過 bzip2 壓縮之後,反而會變大,大家可以拿比較大一點的資料來測試。
zip
Python 的 zipfile
模組可以用來把多個檔案打包壓縮成一個 zip 壓縮檔,或是將一個 zip 壓縮檔解壓縮。
建立 zip 壓縮檔
這個範例會將 file1.txt
與 file2.png
這兩個檔案打包起來,壓縮成一個 archive.zip
壓縮檔案:
import zipfile with zipfile.ZipFile('archive.zip', 'w') as zf: zf.write('file1.txt') zf.write('file2.png')
解壓縮 zip 檔案
這個範例會將上面建立好的 archive.zip
解壓縮:
import zipfile with zipfile.ZipFile('archive.zip', 'r') as zf: open('file1.txt', 'w').write(zf.read('file1.txt')) open('file2.png', 'wb').write(zf.read('file2.png'))
tar
Python 的 tarfile
模組可以針對各種 tar 壓縮檔進行壓縮與解壓縮。
解壓縮 tar.gz 檔案
將 archive.tar.gz
這個壓縮檔在目前的目錄中解壓縮:
import tarfile with tarfile.open("archive.tar.gz") as tf: tf.extractall()
建立 tar 檔案
這個範例會將 file1.txt
與 file2.png
兩個檔案打包成一個未壓縮的 tar 檔案:
import tarfile with tarfile.open("archive.tar", "w") as tf: tf.add("file1.txt") tf.add("file2.png")
建立 tar.gz 檔案
這個範例會將 file1.txt
與 file2.png
兩個檔案打包並壓縮成 archive.tar.gz
:
import tarfile with tarfile.open("archive.tar.gz", "w:gz") as tf: tf.add("file1.txt") tf.add("file2.png")
列出 tar.gz 檔案內容
這個範例會將 archive.tar.gz
壓縮檔中的內容全部列出來,包含檔案名稱、大小與類型:
# -*- coding: utf-8 -*- import tarfile with tarfile.open("archive.tar.gz", "r:gz") as tf: for tarinfo in tf: print "檔名:", tarinfo.name print "大小:", tarinfo.size, "bytes" print "類型:", if tarinfo.isreg(): print "檔案" elif tarinfo.isdir(): print "目錄" else: print "其他"
檔名: file1.txt 大小: 29 bytes 類型: 檔案 檔名: file2.png 大小: 514334 bytes 類型: 檔案
檔案擁有者與群組
tar 壓縮檔可以保留檔案的檔案擁有者與群組資訊,以下是查看 tar 壓縮檔內每個檔案擁有者與群組資訊的 Python 範例:
# -*- coding: utf-8 -*- import tarfile with tarfile.open("archive.tar.gz", "r:gz") as tf: for tarinfo in tf: print "檔名:", tarinfo.name print "擁有者:", tarinfo.uname, ", UID:", tarinfo.uid print "群組:", tarinfo.gname, ", GID:", tarinfo.gid
檔名: file1.txt 擁有者: pi , UID: 1000 群組: pi , GID: 1000 檔名: file2.png 擁有者: pi , UID: 1000 群組: pi , GID: 1000
改變檔案擁有者與群組
在建立 tar 壓縮檔時,我們可以改變原本檔案的擁有者與群組資訊,以下是將每個檔案的擁有者與群組都設定為 root
的範例:
import tarfile def reset(tarinfo): tarinfo.uid = tarinfo.gid = 0 tarinfo.uname = tarinfo.gname = "root" return tarinfo with tarfile.open("archive.tar.gz", "w:gz") as tf: tf.add("file1.txt", filter = reset) tf.add("file2.png", filter = reset)
這裡我們加入一個 filter,讓每一個檔案在加入 tar 壓縮檔時,自動將擁有者與群組都設定為 root
。
參考資料:Python 官方文件、PyMOTW
Yi
解壓縮 zip 的例子是不是怪怪的?
file() 沒有定義
Wayne
那兩行是open不是file,
open(‘file1.txt’, ‘w’).write(zf.read(‘file1.txt’))
open(‘file2.png’, ‘wb’).write(zf.read(‘file2.png’))
這樓主不太細心呢!
都2023年了XD
G. T. Wang
真是不好意思,太忙了沒看到,剛剛已修正。