243 votes

Pourquoi les fichiers tar.xz sont-ils 15x plus petits lorsqu'on utilise la bibliothèque tar de Python par rapport à tar de macOS ?

Contexte

Je compresse des dossiers d'environ 1,3 Go contenant chacun 1 440 fichiers JSON et je constate que la différence est de 15 fois supérieure entre l'utilisation de la fonction tar et la commande intégrée de Python tarfile sur macOS ou Raspbian 10 (Buster)

Exemple de fonctionnement minimal

Ce script compare les deux méthodes :

#!/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")

La sortie est :

zsh tar filesize: 23.7 MB
py tar filesize: 1.49 MB

Les versions que j'utilise sont les suivantes :

  • tar sur macOS : bsdtar 3.3.2 - libarchive 3.3.2 zlib/1.2.11 liblzma/5.0.5 bz2lib/1.0.6
  • tar sur Raspbian 10 : xz (XZ Utils) 5.2.4 liblzma 5.2.4
  • tarfile Bibliothèque Python : 0.9.0

Les choses que j'ai essayées

Après compression, j'ai extrait les deux archives et comparé le dossier résultant avec :

diff -r py-archive-expanded zsh-archive-expanded

Il n'y avait aucune différence.

Si je compare directement les deux archives tar, elles semblent différentes :

 diff zsh-archive.tar.xz py-archive.tar.xz
Binary files zsh-archive.tar.xz and py-archive.tar.xz differ

Si j'inspecte les archives avec Quicklook (et le plugin Betterzip), je constate que les fichiers de l'archive sont classés d'une manière différente :

La gauche est zsh-archive.tar.xz le droit est py-archive.tar.xz :

Enter image description hereenter image description here

L'archive zsh utilise un ordre inconnu, et l'archive Python ordonne le fichier par date de modification. Je ne suis pas sûr que cela ait de l'importance.

Question

Que se passe-t-il ? Est-ce que je perds quelque chose en utilisant la bibliothèque Python pour compresser mes données ? La différence de taille de 15 fois est-elle un indicateur d'un problème quelconque ? Ou puis-je continuer à utiliser l'implémentation efficace de Python en toute sécurité ?

307voto

Saaru Lindestøkke Points 4331

Réponse courte : oui, l'utilisation de Python est sûre. tarlib pour compresser les données, rien n'est perdu par rapport à BSD tar .

Question sous-jacente : le tri

Je pense que le problème sous-jacent est que BSD tar et GNU tar sans aucune option met les fichiers dans l'archive dans un ordre indéfini.

GNU tar a un --sort option :

trier les entrées du répertoire en fonction de ORDER qui est l'un des none , name o inode .
La valeur par défaut est --sort=none qui stocke les membres de l'archive dans le même ordre que celui renvoyé par le système d'exploitation.

Test de GNU tar

Pour tester cela, j'ai installé GNU tar sur mon Mac avec :

brew install gnu-tar

Et puis j'ai taré le même dossier, mais avec l'option --sort option :

gtar --sort='name' -cJf zsh-archive-sorted.tar.xz /Users/user/Desktop/temp/tar/2021-03-11

Le site zsh-archive-sorted.tar.xz est de 1,5 Mo, ce qui correspond à la taille de l'archive créée par la bibliothèque Python.

Concaténation dans l'ordre trié

L'effet du tri sur la taille finale de l'archive est démontré en concaténant d'abord tous les fichiers JSON triés par nom (avec l'heure de création au début) et en les taillant ensuite avec BSD tar :

cat *.json > all.txt
tar cJf zsh-cat-archive.tar.xz all.txt

Le site zsh-cat-archive.tar.xz L'archive est également de 1,5 MB.

Python tarfile trier

Enfin, le la documentation de l'application Python TarFile.add fonction confirme que Python tarfile trie par défaut :

Les répertoires sont ajoutés récursivement par défaut. Ceci peut être évité en mettant recursive à False. La récursion ajoute les entrées dans un ordre trié.

Pourquoi le tri est important

Je pense que la raison pour laquelle le tri a un tel impact dans mon cas est la suivante :

Mes fichiers JSON contiennent les emplacements de centaines de véhicules. Chaque minute, je lis tous les emplacements, mais seuls quelques-uns de ces emplacements ont une valeur différente d'une minute à l'autre.
En triant les fichiers par nom, deux fichiers successifs ont peu de caractères différents entre eux. Apparemment, cela est très favorable à l'efficacité de la compression.

6voto

Giacomo1968 Points 48326

Essayez de définir les niveaux de compression dans la ligne de commande de macOS.

Je sais que vous demandez xz mais expliqué dans cette réponse ici Sur les anciennes versions de GZip, vous pouvez définir le niveau de compression avec une variable d'environnement comme celle-ci :

GZIP=-9 tar cf zsh-archive.tar.xz folderpath

Cela dit, cela ne semble fonctionner qu'avec GZip 1.8 et est déprécié sur les versions ultérieures. Utilisez donc l'option -I / --use-compress-program=COMMAND pour tar à la place ; notez que cette option peut ne pas fonctionner sur macOS mais placez-la ici de toute façon juste au cas où. La commande deviendrait donc :

tar -I 'gzip -9' -cf zsh-archive.tar.xz folderpath

Et oui, dans ces exemples, l'archive serait compressée avec Gzip au lieu de xz mais vous pouvez facilement changer la commande en ceci pour utiliser xz comme ça :

tar -I 'xz -9' -cf zsh-archive.tar.xz folderpath

Le site xz Le niveau de compression varie de -0 a -9 la valeur par défaut étant -6 donc -9 est le niveau de compression le plus élevé.

Notez simplement que xz n'est pas installé par défaut sur macOS. Pour l'installer sur macOS, vous devez d'abord installer Homebrew et ensuite installer xz via Homebrew comme ceci :

brew install xz

4voto

Louis Thompson Points 41

Je me demande ce que Python utilise pour la compression.

http://tukaani.org/xz/

Il utilise probablement les appels de fonction dans liblzma. Goudron passe probablement par la commande xz Shell.

Un bref commentaire sur --sort=name :

L'option sort est une amélioration relativement récente de GNU tar et a été introduite dans tar version 1.28.

Il se peut qu'il ne soit jamais implémenté dans BSD tar.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X