這裡介紹如何在 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.compressbz2.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.txtfile2.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:
  file('file1.txt', 'w').write(zf.read('file1.txt'))
  file('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.txtfile2.png 兩個檔案打包成一個未壓縮的 tar 檔案:

import tarfile
with tarfile.open("archive.tar", "w") as tf:
  tf.add("file1.txt")
  tf.add("file2.png")

建立 tar.gz 檔案

這個範例會將 file1.txtfile2.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