CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: tarfile で tar ファイルを圧縮・展開する

Python の標準ライブラリには tarfile というモジュールがある。 このモジュールを使うと tar 形式で複数のファイルをまとめることができる。 また tarfile モジュールは gzip や bzip2 といった形式の圧縮・展開もサポートしている。 今回は、そんな tarfile モジュールで、利用する場面の多い tar 形式でまとめて gzip 形式で圧縮したファイル (tar.gz) を扱ってみる。

使った環境は次のとおり。

$ sw_vers
ProductName:        macOS
ProductVersion:     13.5
BuildVersion:       22G74
$ python -V
Python 3.10.12
$ tar --version
bsdtar 3.5.3 - libarchive 3.5.3 zlib/1.2.11 liblzma/5.0.5 bz2lib/1.0.8

もくじ

tar ファイルを展開する

まずは extraction.txt というテキストファイルが 1 つ入った tar.gz ファイルを用意する。 ファイルは tar(1) コマンドを使って作成して、名前は extraction.tar.gz にした。

$ echo "Hello, World" > extraction.txt
$ tar czvf extraction.tar.gz extraction.txt 
a extraction.txt
$ file extraction.tar.gz 
extraction.tar.gz: gzip compressed data, last modified: Tue Aug 20 03:03:04 2023, from Unix, original size modulo 2^32 2048

上記のファイルを Python の tarfile モジュールで展開してみる。 以下のサンプルコードでは、アーカイブに含まれるファイルのバイト列を読み取ってファイル名と共に出力している。 tarfile.open() 関数は、モードに "r" を指定すると自動的に圧縮アルゴリズムを読み取って展開の処理をしてくれる。

"""任意の圧縮方式を使った tar ファイルを展開するサンプルコード"""

import tarfile


def main():
    filepath = "extraction.tar.gz"
    with tarfile.open(filepath, mode="r") as tar:
        # アーカイブに含まれるファイルの情報を一覧で取得する
        members: list[tarfile.TarInfo] = tar.getmembers()
        for tar_info in members:
            # ファイル名または TarInfo を指定してファイルオブジェクトにアクセスできる
            with tar.extractfile(tar_info) as file_fp:
                # ファイルの内容を出力する
                print(f"{tar_info.name}: {file_fp.read()}")


if __name__ == "__main__":
    main()

上記を実行してみよう。

$ python extraction.py
extraction.txt: b'Hello, World\n'

ちゃんと含まれている extraction.txt に "Hello, World" という文字列に解釈できるバイト列が含まれることが確認できた。

tar ファイルを作成する

続いては tar ファイルを作成するサンプルコードを示す。 tarfile モジュールの API は、すでにファイルシステムに存在するファイルを扱うものが多い。 しかし、オンメモリのデータをアーカイブにすることも、もちろんできる。 以下では io.BytesIO を使ってファイルライクオブジェクトを作成し、それをアーカイブに含めている。 アーカイブは compression.tar.gz という名前で、アーカイブに含まれるファイル名は compression.txt にした。 なお、gzip 形式で圧縮する場合には tarfile.open() 関数の mode 引数に "w:gz" を指定する。

"""gzip 形式で圧縮した tar ファイルを作成するサンプルコード"""

import tarfile
import io


def main():
    # アーカイブに含めるファイルの内容を用意する
    file_buffer = io.BytesIO()
    file_buffer.write("Hello, World\n".encode("ascii"))
    file_buffer.seek(0)

    # "w:gz" モードでファイルを開くことで gzip で圧縮した tar ファイルになる
    filepath = "compression.tar.gz"
    with tarfile.open(filepath, mode="w:gz") as tar:
        # アーカイブに含めるファイルの名前を指定する
        tar_info = tarfile.TarInfo(name="compression.txt")
        # アーカイブに含めるファイルのサイズを指定する
        tar_info.size = len(file_buffer.getvalue())
        # アーカイブにファイルを追加する
        tar.addfile(tar_info, fileobj=file_buffer)


if __name__ == "__main__":
    main()

上記を実行してみよう。

$ python compression.py

すると compression.tar.gz という名前でアーカイブのファイルができる。

$ file compression.tar.gz 
compression.tar.gz: gzip compressed data, was "compression.tar", last modified: Tue Aug 20 10:50:49 2023, max compression, original size modulo 2^32 10240

tar(1) コマンドを使って展開してみよう。

$ tar zxvf compression.tar.gz              
x compression.txt

すると compression.txt というファイルができる。 内容を確認してみよう。

$ cat compression.txt        
Hello, World

ちゃんとサンプルコードで使った文字列が書き込まれている。

ちなみに、今回はアーカイブの直下にファイルを配置した。 もし、展開したときにファイルをディレクトリに入れたいときは TarInfo の引数 name にスラッシュを含めよう。

まとめ

今回は Python の tarfile モジュールを使って tar ファイルを圧縮・展開してみた。

参考

docs.python.org