[Python] tarによるデータアーカイブと圧縮

Python ファイル操作

tar形式は、ファイルアーカイブのフォーマットの一つです。本来tarはファイルアーカイブのみで圧縮の機能はありませんが、Pythonではtarfileモジュールを使ってファイルアーカイブとデータ圧縮まで行うことが可能です。今回はこのモジュールをの基本的な使い方についてまとめます。

確認した環境

  • OS: Ubuntu 16.04LTS
  • Python: ver3.7.0

tarファイルフォーマットとは

tar形式は、ファイルアーカイブのフォーマットの一つで、UNIX系OSでは標準のフォーマットです。Pythonではtarfileモジュールを使ってファイルのアーカイブ化を実現しますが、圧縮アルゴリズム(gzip、bz2、および lzma)を選択して、データ圧縮も可能です。
尚、ZIPの際はひと工夫が必要でしたが、tarfileモジュールはディレクトリ圧縮も可能です。

この記事で使うフォルダ構成の概要

この記事では、以下のフォルダ構成を例にします。

- カレントディレクトリ:/home/rensyu

- 圧縮ファイルパス:/home/rensyu/testdir2.tar.gz

- 圧縮ファイルのフォルダ構成:testdir2.tar.gz
.
├── sample0
│   └── sample01.txt
├── sample1.txt
└── sample2.txt

TarFileオブジェクト生成

tarアーカイブファイルの読み込み/書き込みは、まずopen()メソッドを使ってTarFileオブジェクトを生成します。

tarfile.open(name=None, mode='r', fileobj=None, bufsize=10240, **kwargs)

引数の設定を以下に示します。mode設定はcompressionパラメータの組み合わせを考えるともっとたくさん設定があるのですが、多すぎるのでここでは主なものだけを記載しました。(詳細は公式サイトを参照)

引数説明
name開きたいアーカイブファイルのパスを文字列で設定
mode =
filemode [:compression]
モード設定
'r' または 'r:*' : 読み込みモード(透過的圧縮(※1))(デフォルト・推奨)
'x' または'x:' : 新規書き込みモード(圧縮なし)(※2)
'a'または'a:' :追加モード(圧縮なし)(※3)
尚、compressionは、gz, bz2, xyを設定可能(一部例外あり)

その他注記事項は以下です。

※1)透過的圧縮(transparent compress): 何かわからなかったので調べると、データを圧縮した状態のまま内容にアクセスできるような圧縮のこと、のようです。(こちらのサイト様を参考にさせて頂きました)
※2)既にファイルが存在していればFileExistsErrorが返ります。
※3)ファイルが存在しなければ新規作成

尚、指定した圧縮方式が開こうとするファイルに対し適切でないとReadErrorとなります。また指定した圧縮方式がサポートされていない場合CompressionErrorとなります。

ここで、TarFileオブジェクトについてもう少し掘り下げてみます。
以下のコードは、tarアーカイブファイルに含まれるファイルの一覧を出力するものです。

>>> import tarfile

# tarfileオブジェクトを生成
>>> tar = tarfile.open('./testdir2.tar.gz', 'r')

# tarアーカイブに含まれるファイル/フォルダ名を取得
>>> for tarinfo in tar:
...    tarinfo.name
... 
'./testdir2'
'./testdir2/sample0'
'./testdir2/sample0/sample01.txt'
'./testdir2/sample1.txt'
'./testdir2/sample2.txt'

# tarfileオブジェクトをクローズ
>>> tar.close()

このコードでtarfileオブジェクトの中身がなんとなく分かると思いますが、もう少し順を追って見ていきます。TarFileオブジェクトをリスト化してみると、、、

>>> list(tar)
[<TarInfo './testdir2' at 0x7f23ebc9e4f8>,
 <TarInfo './testdir2/sample0' at 0x7f23ece17b38>,
 <TarInfo './testdir2/sample0/sample01.txt' at 0x7f23ece17d90>,
 <TarInfo './testdir2/sample1.txt' at 0x7f23ebc9e1d8>, 
 <TarInfo './testdir2/sample2.txt' at 0x7f23ebc9e2a0>]

中身はTarInfoオブジェクトの集合で構成されています。これらのname属性を確認すると以下のようにフォルダ名が得られます。

# 例えば、最初の要素のname属性を確認します
>>> list(tar)[0].name
'./testdir2'

ちなみに、TarFileオブジェクト生成はwithステートメントで記載することも出来ます。withステートメントで書いたコードは以下。

>>> import tarfile
>>> with tarfile.open('./testdir2.tar.gz', 'r:*') as tar:
...     for tarinfo in tar:
...         tarinfo.name
... 
'./testdir2'
'./testdir2/sample0'
'./testdir2/sample0/sample01.txt'
'./testdir2/sample1.txt'
'./testdir2/sample2.txt'

以降、tarfileオブジェクトの生成はwithステートメントで記載します。

tarファイルの展開

extractall()メソッドで展開できます。

TarFile.extractall(path=".", members=None, *, numeric_owner=False)

第一引数にファイルを展開する場所(フォルダ)を指定します。指定がなければカレントフォルダに展開されます。

>>> import tarfile
>>> with tarfile.open('./testdir2.tar.gz', 'r:*') as tar:
...     tar.extractall('./extracted')

結果を確認します。設定したとおりextractedフォルダに展開されています。

/home/rensyu$ tree
.
├── extracted      ← ここに展開されました
│   └── testdir2
│       ├── sample0
│       │   └── sample01.txt
│       ├── sample1.txt
│       └── sample2.txt
└── testdir2.tar.gz

tarファイルの作成

tarfile.open()メソッドでTarFileオブジェクトを書き込みモード(圧縮モードはここではgzip)で開いた後に、add()メソッドで圧縮したいファイルを追加していきます。ちなみに拡張子は、tarフォーマットでアーカイブしてgzipで圧縮しているので‘.tar.gz’と表記しています。
尚、ZipFileオブジェクトと異なり、フォルダでもファイルでもtarファイルを作成できます
ここでは、上記例で展開したtestdir2フォルダを丸ごとgzipで圧縮する例を記載します。

>>> import tarfile
>>> with tarfile.open('./compressed.tar.gz', 'w:gz') as tar:
...     tar.add('./extracted/testdir2')
... 
>>>

フォルダ構成を確認してみます。

/home/rensyu$ tree
.
├── compressed.tar.gz ← ここにtarファイルが作成されました
├── extracted
│   └── testdir2
│       ├── sample0
│       │   └── sample01.txt
│       ├── sample1.txt
│       └── sample2.txt
└── testdir2.tar.gz

まとめ

今回はtarファイルフォーマットによるファイルアーカイブとデータ圧縮の基本についてまとめました。

参考書籍

書籍でもう少し詳しく学びたい場合はこちらもどうぞ。筆者もかなり参考にさせてもらっています!

シェアする
ひびきをフォローする
Hbk project