Почему tar.xz-файлы, созданные с Python tar, в 15 раз меньше, чем у macOS tar

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Прим. перев.: это не совсем обычный перевод, потому что в его основе не отдельно взятая статья, а недавний случай со Stack Exchange, ставший главным хитом ресурса в этом месяце. Его автор задает вопрос, ответ на который можно отнести к базовым знаниям в области ИТ, но в то же время оказавшийся откровением для некоторых посетителей сайта.

Сжимая каталоги по ~1,3 ГБ, в каждом из которых по 1440 файлов JSON, я обнаружил 15-кратную разницу между размером архивов, сжатых с помощью tar на macOS или Raspbian 10 (Buster), и архивов, полученных при использовании библиотеки tarfile, встроенной в Python.

Минимальный рабочий пример

В этом скрипте сравниваются оба метода:

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

Разницы не было.

Однако при сравнении двух архивов «как есть» (их бинарные представления) они выглядят разными:

➜ 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-archive.tar.xz, справа — py-archive.tar.xz.

В архиве zsh файлы упорядочены по неизвестному принципу, а в архиве Python — по дате изменения. Возможно, это имеет значение.

Вопрос

Что происходит? В чем подвох? Чем я жертвую, используя Python-библиотеку для сжатия данных? Намекает ли 15-кратная разница в размере на наличие какой-либо проблемы или можно спокойно продолжать использовать более эффективную Python-реализацию?

Ответ

Краткий ответ: да, tarlib в Python можно использовать для сжатия данных; по сравнению с BSD-реализацией tar ничем жертвовать не приходится.

Основная проблема: сортировка

Думаю, что главная проблема в том, что BSD- и GNU-версии tar без опций сортировки добавляют файлы в архив в неопределенном порядке.

В GNU tar есть параметр --sort:

Сортирует содержимое директории в соответствии с определенным порядком ORDER, который может быть none, name или inode.

По умолчанию --sort=none — файлы добавляются в архив в том порядке, в котором их возвращает операционная система.

Тестирование GNU tar

Перед проведением испытаний я установил GNU tar на Mac:

brew install gnu-tar

А потом за'tar'ил тот же каталог, но с опцией --sort:

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

Размер архива zsh-archive-sorted.tar.xz составляет 1,5 МБ — такой же, как у архива, полученного с помощью Python-библиотеки.

Конкатенация в отсортированном порядке

Эффект, который сортировка оказывает на конечный размер архива, еще лучше заметен при конкатенации JSON-файлов, предварительно отсортированных по названию (в его начале идет время создания — unixtime), а затем заархивированных с помощью BSD tar:

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

Размер архива zsh-cat-archive.tar.xz также равен 1,5 МБ.

Сортировка в Python-библиотеке tarfile

Наконец, документация к функции TarFile.add в Python подтверждает, что библиотека tarfile в Python по умолчанию сортирует файлы:

По умолчанию директории добавляются рекурсивно. Этого можно избежать, установив recursive в False. Рекурсия добавляет записи в отсортированном порядке.

Почему сортировка имеет значение

Думаю, что причина, по которой сортировка оказывает столь значительно влияние на размер архива, в моем случае состоит в следующем:

JSON-файлы содержат местоположения сотен транспортных средств. Эти местоположения считываются ежеминутно, но только некоторые из них меняются от минуты к минуте.

В результате сортировки по имени рядом оказываются файлы, мало отличающиеся друг от друга. Судя по всему, это весьма благоприятно сказывается на эффективности сжатия.

P.S. от переводчика

Читайте также в нашем блоге:

  • «Git happens! 6 типичных ошибок Git и как их исправить»;

  • «Больше разработчиков должны знать это о базах данных»;

  • «Взгляд на технологии последнего десятилетия».

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Очевидным ли был ответ для вас?

  • 100,0%Да, сразу догадался(ась)1
  • 0,0%Да, но не успел(а) предугадать во время чтения0
  • 0,0%Нет0
Источник: https://habr.com/ru/company/flant/blog/548428/


Интересные статьи

Интересные статьи

Жажда тюнинга может завести в неведомые дебри. И, пожалуй, едва ли не самая частая неправильная оптимизация - отключение swap-файла. Если прикинуть частоту, с которой эта ошибка встречает...
Привет, Хабр! К огромному удовлетворению нашей читательской аудитории, наша работа над обновлением книг по Python не прекращается. Но не прекращается и поиск в этом направлении — и сег...
Вот есть JavaScript — прекрасная вещь. И прекрасная она по большей части потому, что дебаггер и отладочные инструменты встроены в каждый Браузер. Без дебаггера и инспектора DOM-дерева...
Знаете, что общего между ситуацией с уничтожением антенн сотовой связи и последней лентой Тарантино «Однажды в Голливуде»? Они оба делят людей на два противоположных лагеря. Читать ...
Wireshark Foundation выпустила финальную stable-версию популярного сетевого анализатора трафика — Wireshark 3.0.0. В новом релизе устранено несколько багов, реализована возможность анализа новы...