コンテクスト
tar
私は1440個のJSONファイルで満たされた約1.3GBのフォルダを圧縮していますが、コマンドとPythonの組み込み関数の使用では15倍の違いがあることがわかりました。tarfile
macOSのライブラリまたはラズビアン10(バスター)
最小限の動作例
このスクリプトは両方の方法を比較します:
#!/usr/bin/env python3
from pathlib import Path
from subprocess import call
import tarfile
fullpath = Path("/Users/user/Desktop/temp/tar/2021-03-11")
zsh_out = Path(fullpath.parent, "zsh-archive.tar.xz")
py_out = Path(fullpath.parent, "py-archive.tar.xz")
# tar using terminal
# tar cJf zsh-archive.tar.xz folderpath
call(["tar", "cJf", zsh_out, fullpath])
# tar using tarfile library
with tarfile.open(py_out, "w:xz") as tar:
tar.add(fullpath, arcname=fullpath.stem)
# Print filesizes
print(f"zsh tar filesize: {round(Path(zsh_out).stat().st_size/(1024*1024), 2)} MB")
print(f"py tar filesize: {round(Path(py_out).stat().st_size/(1024*1024), 2)} MB")
出力は次のようになります。
zsh tar filesize: 23.7 MB
py tar filesize: 1.49 MB
私が使用しているバージョンは次のとおりです。
tar
macOSの場合:bsdtar 3.3.2 - libarchive 3.3.2 zlib/1.2.11 liblzma/5.0.5 bz2lib/1.0.6
tar
Raspbian 10の場合:xz (XZ Utils) 5.2.4 liblzma 5.2.4
tarfile
Python ライブラリ:0.9.0
私が試したこと
圧縮後、両方のアーカイブを抽出し、結果のフォルダーを次のものと比較しました。
diff -r py-archive-expanded zsh-archive-expanded
違いはありませんでした。
2 つの tar アーカイブを直接比較すると、異なるように見えます。
➜ diff zsh-archive.tar.xz py-archive.tar.xz
Binary files zsh-archive.tar.xz and py-archive.tar.xz differ
Quicklook (および Betterzip プラグイン) を使用してアーカイブを検査すると、アーカイブ内のファイルが異なる順序で並べられていることがわかります。
左はzsh-archive.tar.xz
、右はpy-archive.tar.xz
:
zsh アーカイブは不明な順序を使用し、Python アーカイブはファイルを変更日順に順序付けます。それが重要かどうかはわかりません。
質問
何が起こっているのでしょうか? Python ライブラリを使用してデータを圧縮すると、何かが失われるのでしょうか? サイズの 15 倍の違いは、何らかの問題を示しているのでしょうか? それとも、効率的な Python 実装を安全に使用できますか?
答え1
tarlib
短い答え: はい、 Python を使用してデータを圧縮するのは安全です。BSD と比較して何も失われませんtar
。
根本的な問題: 並べ替え
tar
根本的な問題は、ソート オプションのない BSDと GNUtar
ではアーカイブ内のファイルが未定義の順序で配置されるということだと思います。
GNUにはオプションtar
があります--sort
:
ディレクトリ エントリを に従って並べ替えます。は、、 、
ORDER
のいずれかです。 デフォルトは で、オペレーティング システムによって返される順序と同じ順序でアーカイブ メンバーを格納します。none
name
inode
--sort=none
GNUのテストtar
tar
これをテストするために、私はMac にGNU をインストールしました:
brew install gnu-tar
次に、同じフォルダーを次の--sort
オプションで tar で圧縮しました。
gtar --sort='name' -cJf zsh-archive-sorted.tar.xz /Users/user/Desktop/temp/tar/2021-03-11
アーカイブzsh-archive-sorted.tar.xz
は 1.5 MB で、Python ライブラリによって作成されたアーカイブのサイズと同じです。
ソート順に連結する
ソートが最終的なアーカイブ サイズに与える影響は、まずすべての JSON ファイルを名前 (先頭に作成 unixtime がある) でソートして連結し、次に BSD で tar することでさらに実証されますtar
。
cat *.json > all.txt
tar cJf zsh-cat-archive.tar.xz all.txt
アーカイブzsh-cat-archive.tar.xz
も 1.5 MB です。
Pythontarfile
ソート
最後に、PythonTarFile.add
関数のドキュメントPython がtarfile
デフォルトでソートすることを確認します。
デフォルトでは、ディレクトリは再帰的に追加されます。これは、recursive を False に設定することで回避できます。再帰により、エントリはソートされた順序で追加されます。
並べ替えが重要な理由
私の場合、ソートがこのような影響を与える理由は次の通りだと思います。
私の JSON ファイルには、何百台もの車両の位置が含まれています。毎分すべての位置を読み取りますが、分ごとに値が異なるのはこれらの位置のうちのほんの一部だけです。
ファイルを名前で並べ替えると、後続の 2 つのファイルにはわずかな違いの文字があります。どうやら、これは圧縮効率に非常に有利なようです。
答え2
macOS コマンドラインで圧縮レベルを設定してみてください。
あなたが尋ねていることは分かっていますxz
しかし、この答えはここにありますGZip の古いバージョンでは、次のように環境変数を使用して圧縮レベルを設定できます。
GZIP=-9 tar cf zsh-archive.tar.xz folderpath
ただし、これは GZip 1.8 でのみ機能し、それ以降のバージョンでは非推奨です。そのため、代わりに tar の-I
/--use-compress-program=COMMAND
オプションを使用してください。このオプションは macOS では機能しない可能性がありますが、念のためここに配置しておきます。そのため、コマンドは次のように変更されます。
tar -I 'gzip -9' -cf zsh-archive.tar.xz folderpath
はい、これらの例ではアーカイブを ではなく Gzip で圧縮しますが、次のようxz
にコマンドを簡単に変更して使用できます。xz
tar -I 'xz -9' -cf zsh-archive.tar.xz folderpath
圧縮xz
レベルの範囲は から で-0
、-9
デフォルトは です-6
。-9
最高の圧縮レベルは です。
macOSではデフォルトではインストールされていないので注意してくださいxz
。macOSにインストールするには、まず自家製そしてインストールするxz
Homebrew 経由で次のようにします:
brew install xz