Kontext
Ich komprimiere Ordner mit einer Größe von ca. 1,3 GB, die jeweils mit 1440 JSON-Dateien gefüllt sind, und stelle fest, dass es einen 15-fachen Unterschied zwischen der Verwendung des tar
Befehls und der in Python integriertentarfile
Bibliothek auf macOS oderRaspbian 10(Buster)
Minimales funktionierendes Beispiel
Dieses Skript vergleicht beide Methoden:
#!/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")
Die Ausgabe ist:
zsh tar filesize: 23.7 MB
py tar filesize: 1.49 MB
Die von mir verwendeten Versionen sind die folgenden:
tar
unter macOS:bsdtar 3.3.2 - libarchive 3.3.2 zlib/1.2.11 liblzma/5.0.5 bz2lib/1.0.6
tar
auf Raspbian 10:xz (XZ Utils) 5.2.4 liblzma 5.2.4
tarfile
Python-Bibliothek:0.9.0
Dinge, die ich versucht habe
Nach der Komprimierung habe ich beide Archive extrahiert und den resultierenden Ordner mit Folgendem verglichen:
diff -r py-archive-expanded zsh-archive-expanded
Es gab keinen Unterschied.
Wenn ich die beiden Tar-Archive direkt vergleiche, scheinen sie unterschiedlich zu sein:
➜ diff zsh-archive.tar.xz py-archive.tar.xz
Binary files zsh-archive.tar.xz and py-archive.tar.xz differ
Wenn ich die Archive mit Quicklook (und dem Betterzip-Plugin) untersuche, sehe ich, dass die Dateien im Archiv anders angeordnet sind:
Links ist zsh-archive.tar.xz
, rechts ist py-archive.tar.xz
:
Das Zsh-Archiv verwendet eine unbekannte Reihenfolge und das Python-Archiv sortiert die Dateien nach Änderungsdatum. Ich bin nicht sicher, ob das wichtig ist.
Frage
Was ist hier los? Verliere ich etwas, wenn ich die Python-Bibliothek zum Komprimieren meiner Daten verwende? Ist der 15-fache Größenunterschied ein Hinweis auf ein Problem? Oder kann ich unbesorgt die effiziente Python-Implementierung verwenden?
Antwort1
tarlib
Kurze Antwort: Ja, es ist sicher, Python zum Komprimieren der Daten zu verwenden , im Vergleich zu BSD geht nichts verloren tar
.
Grundlegendes Problem: Sortieren
Ich denke, das zugrunde liegende Problem besteht darin, dass BSD tar
und GNU tar
ohne Sortieroptionen die Dateien im Archiv in einer undefinierten Reihenfolge ablegen.
GNU tar
hat eine --sort
Option:
Sortieren Sie Verzeichniseinträge nach
ORDER
, was eines der folgenden istnone
: ,name
, oderinode
.
Die Standardeinstellung ist--sort=none
, wodurch Archivelemente in derselben Reihenfolge gespeichert werden, wie sie vom Betriebssystem zurückgegeben wird.
GNU testentar
Um dies zu testen, habe ich GNU tar
auf meinem Mac mit folgendem installiert:
brew install gnu-tar
Und dann den gleichen Ordner getarnt, allerdings mit der --sort
Option:
gtar --sort='name' -cJf zsh-archive-sorted.tar.xz /Users/user/Desktop/temp/tar/2021-03-11
Das zsh-archive-sorted.tar.xz
Archiv ist 1,5 MB groß und entspricht der Größe des von der Python-Bibliothek erstellten Archivs.
Verketten in sortierter Reihenfolge
Die Auswirkung der Sortierung auf die endgültige Archivgröße wird weiter demonstriert, indem zunächst alle nach Namen sortierten JSON-Dateien (die die Erstellungs-Unixzeit am Anfang haben) aneinandergereiht und dann mit BSD getarnt werden tar
:
cat *.json > all.txt
tar cJf zsh-cat-archive.tar.xz all.txt
Das zsh-cat-archive.tar.xz
Archiv ist ebenfalls 1,5 MB groß.
Python- tarfile
Sortierung
Endlich, dasDokumentation der Python TarFile.add
-Funktionbestätigt, dass Python tarfile
standardmäßig sortiert:
Verzeichnisse werden standardmäßig rekursiv hinzugefügt. Dies kann vermieden werden, indem rekursiv auf False gesetzt wird. Rekursion fügt Einträge in sortierter Reihenfolge hinzu.
Warum das Sortieren wichtig ist
Ich denke, der Grund, warum die Sortierung in meinem Fall einen solchen Einfluss hat, ist folgender:
Meine JSON-Dateien enthalten die Standorte von Hunderten von Fahrzeugen. Jede Minute lese ich alle Standorte aus, aber nur wenige dieser Standorte haben von Minute zu Minute einen anderen Wert.
Durch die Sortierung der Dateien nach Namen weisen zwei aufeinanderfolgende Dateien kaum unterschiedliche Zeichen auf. Offensichtlich ist dies sehr förderlich für die Komprimierungseffizienz.
Antwort2
Versuchen Sie, die Komprimierungsstufen in der macOS-Befehlszeile einzustellen.
Ich weiß, Sie fragen sichxz
aber erklärt indiese Antwort hier, bei älteren Versionen von GZip können Sie die Komprimierungsstufe mit einer Umgebungsvariablen wie dieser festlegen:
GZIP=-9 tar cf zsh-archive.tar.xz folderpath
Allerdings scheint das nur mit GZip 1.8 zu funktionieren und wird in späteren Versionen nicht mehr verwendet. Verwenden Sie stattdessen die Option -I
/ --use-compress-program=COMMAND
für tar. Beachten Sie, dass diese Option unter macOS möglicherweise nicht funktioniert, aber setzen Sie sie trotzdem hier, nur für alle Fälle. Der Befehl würde sich dann ändern in:
tar -I 'gzip -9' -cf zsh-archive.tar.xz folderpath
Und ja, in diesen Beispielen wird das Archiv mit Gzip statt mit komprimiert xz
, aber Sie können den Befehl ganz einfach wie folgt ändern und verwenden xz
:
tar -I 'xz -9' -cf zsh-archive.tar.xz folderpath
Der xz
Komprimierungsgrad reicht von -0
bis, -9
wobei der Standardwert ist -6
; dies -9
ist der höchste Komprimierungsgrad.
Beachten Sie, dass es xz
nicht standardmäßig auf macOS installiert ist. Um es auf macOS zu installieren, müssen Sie zuerst installierenSelbstgebrautesund dann installierenxz
über Homebrew wie folgt:
brew install xz
Antwort3
Ich frage mich, was Python zur Komprimierung verwendet
Es verwendet wahrscheinlich die Funktionsaufrufe in liblzma.Teerwird wahrscheinlich durch den xz-Shell-Befehl weitergeleitet.
Ein kurzer Kommentar zu --sort=name
:
Die Sortieroption ist eine relativ neue Erweiterung von GNU Tar und wurde in Tar Version 1.28 eingeführt.
Es darf nie in BSD Tar implementiert werden.