Python Tips: アーカイブファイル( .zip .tar.gz )を扱いたい

Python で .zip.tar.gz などのアーカイブファイル(圧縮ファイル)を扱う方法についてかんたんにまとめました。

仕様と動作の確認に使用した Python のバージョンは Python 3.9.x です。

Python 2 が主流の頃から Python を使い続けてきた方は、アーカイブファイルの操作といえば標準ライブラリの zipfiletarfile などが真っ先に思い浮かぶ方が多いのではないかと思います。

Python 3 の場合は zipfiletarfile を使うのもよいですがより高レベルの shutil を使うという選択肢もあります。 shutilzipfiletarfile よりもシンプルでわかりやすい(そしてアーカイブ形式によらず共通の)インタフェースを提供しています。

Python 3 でアーカイブファイルの操作が必要になったときは、まず最初に shutil が使えないか検討し、使えたら shutil を使い、使えない場合は zipfiletarfile を使う、とするのがよいのではないかと思います。

それぞれの使い方をかんたんに見てみましょう。

shutil

shutil.zip.tar.gz に対応しています 1 。 両者を共通のシンプルなインタフェース(=関数)で扱えます。

アーカイブファイルを作成する

関数 shutil.make_archive() を使用します。

from shutil import make_archive

# .zip の場合
file_path = make_archive(base_name="/tmp/archived", format="zip", root_dir="/tmp/directory_to_archive")
# => `/tmp/archived.zip`

# .tar.gz の場合
file_path = make_archive(base_name="/tmp/archived", format="gztar", root_dir="/tmp/directory_to_archive")
# => `/tmp/archived.tar.gz`

各引数の意味合いは次のとおりです:

  • base_name: 生成したいアーカイブファイルのパス(拡張子なし)
  • format: アーカイブフォーマット
  • root_dir: アーカイブしたいディレクトリのパス

format"zip" を選べば .zip ファイル、 "gztar" を選べば .tar.gz ファイルが作成されます。

format の選択肢にどのようなものがあるのかは環境により異なり shutil.get_archive_formats() で調べることができます。 私の手元の環境では 5 つのフォーマットが利用可能でした:

shutil.get_archive_formats()
# =>
# [
#  ('bztar', "bzip2'ed tar-file"),
#  ('gztar', "gzip'ed tar-file"),
#  ('tar', 'uncompressed tar file'),
#  ('xztar', "xz'ed tar-file"),
#  ('zip', 'ZIP file'),
# ]

これらの引数のうち root_dir は非必須で、指定しなかった場合はカレントディレクトリがアーカイブ対象になります。

make_archive() には他にも多くの引数があるので、実際に使うときには一度確認することをおすすめします。

shutil.make_archive(base_name, format[, root_dir[, base_dir[, verbose[, dry_run[, owner[, group[, logger]]]]]]])

make_archive() の戻り値は実際に生成されたアーカイブファイルのパス( str )です。 引数 base_nameformat に対応した拡張子が付与されたものになります。

アーカイブファイルを展開する

関数 shutil.unpack_archive() を使用します。

from shutil import unpack_archive

# .zip の場合
unpack_archive(filename="/tmp/archived.zip", extract_dir="/tmp/extracted", format="zip")

# .tar.gz の場合
unpack_archive(filename="/tmp/archived.tar.gz", extract_dir="/tmp/extracted", format="gztar")

各引数の意味合いは次のとおりです:

  • filename: 展開したいアーカイブファイルのパス
  • extract_dir: 展開先のディレクトリのパス
  • format: アーカイブフォーマット

このうち必須なのは filename だけで、 extract_dirformat は非必須です。 extract_dir を渡さなかった場合、展開先はカレントディレクトリになります。 format を渡さなかった場合、 filename の拡張子に合ったフォーマットが自動的に選択されます。

unpack_archive() の引数は( Python 3.9 では)この 3 つのみです。

shutil.unpack_archive(filename[, extract_dir[, format]])

unpack_archive() に戻り値はありません(戻り値 None です)。

zipfile

from zipfile import ZipFile

アーカイブファイルを作成する

zipfile.ZipFile オブジェクトのメソッド write() writestr() などを使用します。 `ZipFile()

ファイルをアーカイブファイルに格納する:

# サンプルファイルを用意
with open("/tmp/sample.txt", "w") as f:
    f.write("はい、タケコプター!")

with ZipFile(file="/tmp/archived.zip", mode="w") as myzip:
    myzip.write(filename="/tmp/sample.txt", arcname="sample.txt") 

文字列を直接アーカイブファイルに格納する:

with ZipFile(file="/tmp/archived.zip", mode="w") as myzip:
    myzip.writestr(zinfo_or_arcname="sample.txt", data="はい、どこでもドア!") 

ZipFile() の引数 mode w は書き込みモードを意味します。 w の他に a (追加モード)、 x (排他的な書き込みモード)もあります。

アーカイブファイルを展開する

zipfile.ZipFile オブジェクトのメソッド read() extract() extractall() などを使用します。

個別の中身だけ読み込む:

with ZipFile(file="/tmp/archived.zip", mode="r") as myzip:
    data = myzip.read(name="sample2.txt")

ファイルを 1 つ取り出す:

with ZipFile(file="/tmp/archived.zip", mode="r") as myzip:
    myzip.extract(member="sample2.txt", path="/tmp/extracted")

中身をすべて取り出す:

with ZipFile(file="/tmp/archived.zip", mode="r") as myzip:
    myzip.extractall(path="/tmp/extracted")

ZipFile() の引数 mode r は読み込みモードを意味します。

展開せずに中身を確認する

zipfile.ZipFile オブジェクトのメソッド infolist() namelist() などを使用します。

with ZipFile(file="/tmp/archived.zip", mode="r") as myzip:
    infolist = myzip.infolist()
    print(infolist)  # -> list[ZipInfo]

tarfile

import tarfile

アーカイブファイルを作成する

tarfile.TarFile オブジェクトのメソッド add() addfile() などを使用します。 tarfile.TarFile オブジェクトは tarfile.open() のコンテキストマネージャで取得できます。

ファイルをアーカイブファイルに格納する:

# サンプルファイルを用意
with open("/tmp/sample.txt", "w") as f:
    f.write("はい、タケコプター!")

with tarfile.open(name="/tmp/archived.tar.gz", mode="w:gz") as mytar:
    mytar.add(name="/tmp/sample.txt", arcname="sample.txt")

文字列を直接アーカイブファイルに格納する:

import io

text = "はい、カムカムキャット!".encode("utf8")

with tarfile.open(name="/tmp/archived.tar.gz", mode="w:gz") as mytar:
    tarinfo = tarfile.TarInfo("sample.txt")
    tarinfo.size = len(text)
    fileobj = io.BytesIO(text)
    mytar.addfile(tarinfo, fileobj)

tarfile.open() の引数 modew:gz は書き込みモードで gzip を意味します。

アーカイブファイルを展開する

tarfile.TarFile オブジェクトのメソッド extract() extractfile() extractall() などを使用します。

個別の中身だけ読み込む:

with tarfile.open(name="/tmp/archived.tar.gz", mode="r:gz") as mytar:
    fileobj = mytar.extractfile("sample.txt")
    data = fileobj.read()

ファイルを 1 つ取り出す:

with tarfile.open(name="/tmp/archived.tar.gz", mode="r:gz") as mytar:
    mytar.extract(member="sample.txt", path="/tmp/extracted")

中身をすべて取り出す:

with tarfile.open(name="/tmp/archived.tar.gz", mode="r:gz") as mytar:
    mytar.extractall(path="/tmp/extracted")

tarfile.open() の引数 moder:gz は読み込みモードで gzip を意味します。

展開せずに中身を確認する

tarfile.TarFile オブジェクトのメソッド next() getmembers() getnames() などを使用します。

1 件ずつ取得する:

with tarfile.open(name="/tmp/archived.tar.gz", mode="r:gz") as mytar:
    while (tarinfo := mytar.next()):
        print(tarinfo.name)  # -> str

全件取得する:

with tarfile.open(name="/tmp/archived.tar.gz", mode="r:gz") as mytar:
    members = mytar.getmembers()
    print(members)  # -> list[TarInfo]

コマンドラインで使用する

zipfile モジュールと tarfile モジュールは python -m でコマンドラインから使用することもできます。 どちらも共通のオプションを提供しています。

  • -c: 作成
  • -e: 展開
  • -l: 確認
  • -t: ファイルが壊れていないかどうかのチェック

zipfile

# 作成する
python -m zipfile -c monty.zip spam.txt eggs.txt

# 展開する
python -m zipfile -e monty.zip target-dir/

# 中身を確認する
python -m zipfile -l monty.zip

tarfile

# 作成する
python -m tarfile -c monty.tar  spam.txt eggs.txt

# 展開する
python -m tarfile -e monty.tar  other-dir/

# 中身を確認する
python -m tarfile -l monty.tar

まとめ

ということで、 Python で .zip.tar.gz などのアーカイブファイル(圧縮ファイル)を扱う方法のまとめでした。

ライブラリ 作成 展開 確認
shutil make_archive() unpack_archive() (なし)
zipfile ZipFile(file, mode="w") ZipFile(file, mode="r") ZipFile(file, mode="r")
tarfile tarfile.open(file, mode="w:gz") tarfile.open(file, mode="r:gz") tarfile.open(file, mode="r:gz")

参考


  1. 正確には .zip には zlib モジュールが、 .tar.gz には zlib モジュールがそれぞれ利用できる必要があります。また、対応するモジュールが利用できる環境では tar.bz2tar.xz など他のアーカイブ形式にも対応しています。