Почему Zip способен сжимать один файл меньше, чем несколько файлов с одинаковым содержимым?

126

Предположим, у меня есть 10000 XML-файлов. Теперь предположим, что я хочу отправить их другу. Перед отправкой я бы хотел их сжать.

Способ 1: не сжимайте их

Результаты:

Resulting Size: 62 MB
Percent of initial size: 100%

Способ 2: Zip каждый файл и отправьте ему 10000 XML-файлов

Команда:

for x in $(ls -1) ;  do   echo $x ; zip "$x.zip" $x ; done

Результаты:

Resulting Size: 13 MB
Percent of initial size: 20%

Способ 3: создать один ZIP-файл, содержащий 10000 XML-файлов

Команда:

zip all.zip $(ls -1)

Результаты:

Resulting Size: 12 MB
Percent of initial size: 19%

Способ 4: объединить файлы в один файл и заархивировать его

Команда:

cat *.xml > oneFile.txt ; zip oneFile.zip oneFile.txt

Результаты:

Resulting Size: 2 MB
Percent of initial size: 3%

Вопросов:

  • Почему я получаю такие значительно лучшие результаты, когда просто архивирую один файл?
  • Я ожидал получить значительно лучшие результаты, используя метод 3, чем метод 2, но не получаю. Почему?
  • Это поведение специфично для zip? Если бы я попытался использовать gzip, я получил бы другие результаты?

Дополнительная информация:

$ zip --version
Copyright (c) 1990-2008 Info-ZIP - Type 'zip "-L"' for software license.
This is Zip 3.0 (July 5th 2008), by Info-ZIP.
Currently maintained by E. Gordon.  Please send bug reports to
the authors using the web page at www.info-zip.org; see README for details.

Latest sources and executables are at ftp://ftp.info-zip.org/pub/infozip,
as of above date; see http://www.info-zip.org/ for other sites.

Compiled with gcc 4.4.4 20100525 (Red Hat 4.4.4-5) for Unix (Linux ELF) on Nov 11 2010.

Zip special compilation options:
    USE_EF_UT_TIME       (store Universal Time)
    SYMLINK_SUPPORT      (symbolic links supported)
    LARGE_FILE_SUPPORT   (can read and write large files on file system)
    ZIP64_SUPPORT        (use Zip64 to store large files in archives)
    UNICODE_SUPPORT      (store and read UTF-8 Unicode paths)
    STORE_UNIX_UIDs_GIDs (store UID/GID sizes/values using new extra field)
    UIDGID_NOT_16BIT     (old Unix 16-bit UID/GID extra field not used)
    [encryption, version 2.91 of 05 Jan 2007] (modified for Zip 3)

Изменить: метаданные

Один ответ предполагает, что различие заключается в системных метаданных, которые хранятся в zip-архиве. Я не думаю, что это может быть так. Чтобы проверить, я сделал следующее:

for x in $(seq 10000) ; do touch $x ; done
zip allZip $(ls -1)

Полученный почтовый индекс составляет 1,4 МБ. Это означает, что все еще остается ~ 10 МБ необъяснимого пространства.

sixtyfootersdude
источник
34
Если я не ошибаюсь, именно это явление заставляет людей зарабатывать, .tar.gzа не просто архивировать весь каталог.
CorsiKa
18
Подобный вопрос уже спросил, Tl, д - р использовать твердые 7zip архивы.
Дмитрий Григорьев
3
@sixtyfootersdude В качестве теста для проверки некоторых ответов, можете ли вы попробовать архивировать почтовый индекс, полученный в методе 3? Я подозреваю, что это уменьшит размер файла до уровня, сравнимого со способом 4.
Трэвис
7
Вместо того , чтобы $(ls -1)просто использовать *: for x in *; zip all.zip *
Муру
4
Если вы хотите сделать сжатие с помощью ZIP, вот обходной путь: сначала создайте несжатый ZIP, содержащий все ваши файлы. Затем поместите этот ZIP внутри другого сжатого ZIP.
user20574

Ответы:

129

Zip обрабатывает содержимое каждого файла отдельно при сжатии. Каждый файл будет иметь свой собственный сжатый поток. В алгоритме сжатия есть поддержка (как правило, DEFLATE ) для идентификации повторяющихся разделов. Однако в Zip отсутствует поддержка поиска избыточности между файлами.

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

Алан Шутко
источник
9
Именно поэтому некоторые инструменты сжатия дают вам возможность сжимать файлы по отдельности или как единое целое. (Хотя, как правило, это также означает, что вам нужно распаковать больше архива, чем в противном случае, если вы хотите просмотреть в нем только один файл.)
JAB
28
@JAB: инструменты сжатия, такие как 7z и rar, используют термин «сплошной» архив для упаковки нескольких файлов «голова к хвосту» в большие потоки сжатия. При умеренном размере фрагмента, таком как 64 МБ, для произвольного доступа к одному файлу может потребоваться распаковка до 64 МБ данных с начала блока сжатия, в котором он находится. Вы можете получить достойный компромисс между произвольным доступом и обнаружением избыточности между файлами. 7z может использовать более эффективную (но более медленную для сжатия) схему сжатия LZMA, что является еще одним преимуществом перед zip.
Питер Кордес
Вы говорите, что there is no support in Zip to find redundancy between filesэто в спецификации файла zip?
sixtyfootersdude
6
@sixtyfootersdude Многие алгоритмы сжатия, такие как DEFLATE, работают как поток. Чтобы восстановить достаточно информации для распаковки части потока, вам нужно обработать весь поток до этой точки. Если бы они попытались найти избыточность между файлами, вам пришлось бы распаковать все 1000 файлов, чтобы перейти к последнему. Обычно, так работает tgz. Тем не менее, zip был разработан, чтобы позволить вам извлекать отдельные файлы. tgz создан для того, чтобы быть более «все или ничего»
Cort Ammon
1
@sixtyfootersdude - это правильно. Перефразируя Cort: спецификации pkzip не поддерживают работу с перекрестными файлами. Если они это сделали, то для извлечения одного файла может потребоваться извлечение всего архива (и каждого файла).
Джеймс Снелл
48

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

Упрощенно, если вы сжимаете один файл, словарь, который отображает (короткие) коды в (более длинные) шаблоны, обязательно содержится в каждом результирующем zip-файле; если вы заархивируете один длинный файл, словарь будет «повторно использован» и станет еще более эффективным для всего контента.

Если ваши файлы даже немного похожи (как текст всегда), повторное использование «словаря» становится очень эффективным, и в результате получается намного меньший общий zip.

Aganju
источник
3
ZIP выполняет как архивирование, так и сжатие. Означает ли это, что ZIP сжимает каждый файл по отдельности, даже если все они попадают в один и тот же ZIP-файл?
Gerrit
2
это вроде как - представьте, что вы удалили один файл, вы не хотели бы, чтобы он потратил еще полчаса на повторное сжатие остальных с новым «словарем». - также, вероятно, предполагается, что для разных файлов нужны очень разные «словари».
Aganju
2
Я не понимаю, почему это так. С помощью инструментов Unix я сначала заархивировал бы файл с помощью tar, а затем сжал его с помощью gzip / bz2 / lzma. Алгоритм сжатия не имеет значения, сколько файлов закодировано в архиве. Кроме того, насколько распространено удаление одного файла из сжатого архива? Я не думаю, что когда-либо делал это.
Gerrit
4
Я не согласен, и это, вероятно, хороший способ. Я не проектировал и не писал ZIP. Я просто сказал, что он делает ...
Aganju
16
У @gerrit есть свои проблемы. Zip предназначен для быстрого доступа к любому файлу в архиве - попробуйте распаковать один файл из архива UHA 100 ГиБ, и вы поймете, почему они выбрали именно этот способ. Он также предназначен для добавления - вы можете создать резервную копию zip и просто добавлять (или заменять) файлы по мере необходимости. Все это очень помогает при использовании архивов. Компромисс заключается в том, что если вы сжимаете файлы, которые очень похожи (что не так уж часто), он не может использовать сходства для уменьшения размера архива.
Луаан
43

В Zip каждый файл сжимается отдельно. Противоположностью является «сплошное сжатие», то есть файлы сжимаются вместе. 7-zip и Rar по умолчанию используют сплошное сжатие. Gzip и Bzip2 не могут сжимать несколько файлов, поэтому сначала используется Tar, что дает тот же эффект, что и сплошное сжатие.

Поскольку XML-файл имеет схожую структуру и, возможно, схожий контент, если файлы сжаты вместе, сжатие будет выше.

Например, если файл содержит строку "<content><element name="и компрессор уже обнаружил эту строку в другом файле, он заменит ее небольшим указателем на предыдущее совпадение, если компрессор не использует «сплошное сжатие» при первом вхождении строки в файл будет записан как литерал, который больше.

ggf31416
источник
9

Zip хранит не только содержимое файла, но и метаданные файла, такие как идентификатор пользователя, права доступа, время создания и изменения и так далее. Если у вас есть один файл, у вас есть один набор метаданных; если у вас есть 10 000 файлов, у вас есть 10 000 наборов метаданных.

Майк Скотт
источник
3
Хорошая мысль, но метаданные системы занимают всего 1,4 МБ. Смотрите мое редактирование.
sixtyfootersdude
1
Я не знаком с алгоритмом zip, но метаданные - это не только информация о файле, но и такие вещи, как размер и словарь, возможно некоторая информация о распределении символов. Словарь в непустом текстовом файле будет отличным от нуля. Вероятно, поэтому вы видите, что метаданные в ваших XML-файлах больше, чем в ваших пустых файлах.
Бен Ричардс
Это была моя первая мысль. Информация заголовка почтового файла
WernerCD
Это только объясняет разницу между 2 и 3, а не 4.
Луаан
@Luaan Нет, как в 2, так и в 3 метаданные для всех 10 000 файлов включены в zip-файл или файлы, поэтому общий размер файла практически одинаков. В 4 есть только метаданные для одного файла, а zip-файл намного меньше.
Майк Скотт
7

Опция, пропущенная OP, заключается в том, чтобы сжать все файлы вместе с выключенным сжатием, а затем сжать получившийся архив с максимальным сжатием. Это примерно имитирует поведение сжатых архивов * nix .tar.Z, .tar.gz, .tar.bz и т. Д., Позволяя сжатию использовать избыточность через границы файлов (чего не может сделать алгоритм ZIP при запуске в одном проходят). Это позволяет извлекать отдельные XML-файлы позже, но максимизирует сжатие. Недостатком является то, что процесс извлечения требует дополнительного шага, временно используя гораздо больше дискового пространства, чем было бы необходимо для обычного .zip.

С распространением бесплатных инструментов, таких как 7-Zip, для расширения семейства tar до Windows, нет никаких оснований не использовать .tar.gz или .tar.bz и т. Д., Как у Linux, OS X и BSD. родные инструменты для манипулирования ими.

Монти Хардер
источник
gzip и bzip2 могут оказаться еще хуже, потому что они разработаны с учетом сжатия потоков, поэтому им придется начинать вывод сжатых данных до того, как все данные для сжатия станут известны.
rackandboneman
@rackandboneman: это компромисс, который вы должны сделать при сжатии файлов, размер которых превышает объем памяти, который вы готовы использовать во время сжатия. (Кроме того, количество процессорного времени, необходимого для поиска чего-либо оптимального на глобальном уровне, было бы огромным.) Огромный словарь сжатия также может увеличить объем памяти, необходимый для распаковки . Это опция для LZMA ( xz/ 7-zip). В любом случае, адаптивные словари могут распознавать шаблоны, как только они видны. Это не похоже на то, чтобы просто построить статическую систему кодирования на основе первых 32 КБ. Вот почему gzip не сосет.
Питер Кордес
Мне очень нравится этот "трюк", если вам нужно остаться с форматом почтового индекса. Я не согласен с вашей «нет причин не использовать 7-zip» - если я отправляю файл не техническому другу, я хочу быть уверен, что он сможет легко его открыть. Если я отправлю бизнес-клиенту, тем более.
Wowfunhappy
5

Формат сжатия zip хранит и сжимает каждый файл отдельно. Он не использует повторение между файлами, только внутри файла.

Конкатенация файлов позволяет zip использовать преимущества повторений для всех файлов, что приводит к значительному увеличению сжатия.

Например, скажем, каждый файл XML имеет определенный заголовок. Этот заголовок встречается только один раз в каждом файле, но почти одинаково повторяется во многих других файлах. В методах 2 и 3 zip не может сжать для этого, но в методе 4 это может.

BonsaiOak
источник
3
Как это отличается от одного из трех лучших ответов, которые были опубликованы 5 часов назад?
Xen2050
1
@ Xen2050 Не большая разница, я просто подумал, что смогу объяснить это более четко.
BonsaiOak
1
@BonsaiOak - затем добавьте комментарий к правильному ответу или отредактируйте, если у вас достаточно повторений. Если нет, но ваш комментарий добавляет ясности, кто-то еще может поднять это и отредактировать сообщение в любом случае.
AdamV
@AdamV Я понимаю твою точку зрения. Мой ответ в настоящее время не добавляет никакой полезной информации, хотя, возможно, и сделал, когда я ее написал. Под первым ответом уже есть соответствующие комментарии, поэтому я не вижу смысла их добавлять. Вы говорите, что я должен просто закрыть свой ответ? Какой вред в том, чтобы оставить его открытым?
BonsaiOak
4

Рядом с метаданными, упомянутыми Майком Скоттом, есть также издержки в алгоритме сжатия.

При сжатии нескольких отдельных небольших файлов вам будет очень повезло, что вы сможете сжать их так, что это просто заполняет один блок сжатия. При сжатии одного монолитного блока система может просто продолжать передавать данные в свой алгоритм, игнорируя «границы» (из-за отсутствия лучшего слова) отдельных файлов.

Также известно, что ASCII имеет высокий коэффициент сжатия. Кроме того, XML часто очень повторяется, что делает метаданные большой частью данных, которые не могут быть так легко сжаты, как содержимое XML.

И наконец, если память работает правильно, zip использует что-то вроде словарной кодировки, что особенно эффективно для файлов ASCII и, тем более, для XML из-за их повторяемости

Объяснение сжатия данных: http://mattmahoney.net/dc/dce.html

GapWim
источник
3

Рассмотрим этот XML:

<root>
  <element id="1" />
  <element id="2" /> 
  <other id="3" />
  ...
</root>

XML имеет очень повторяющуюся структуру, Zip использует эти повторы для создания словаря, в котором шаблон встречается чаще, а затем при сжатии использует меньше битов для хранения более повторяющихся шаблонов и больше битов для хранения менее повторяющихся шаблонов .

Когда вы объединяете эти файлы, исходный файл (источник для zip) большой, но содержит гораздо более повторяющиеся шаблоны, потому что распределение большого количества скучных структур XML амортизируется в большом целом файле, давая возможность ZIP сохранять эти шаблоны. используя меньше битов.

Теперь, если вы объедините разные XML в один файл, даже если эти файлы имеют совершенно разные имена тегов, алгоритм сжатия найдет наилучшее распределение шаблонов по всем файлам, а не файл за файлом.

В конечном итоге алгоритм сжатия нашел наилучшее повторное распределение паттернов.

rnrneverdies
источник
-1

В дополнение к ответу 7-Zip есть еще один подход, который не так хорош, но стоит попробовать, если по какой-то причине вы не хотите использовать 7-Zip:

Сожмите почтовый файл. Теперь обычно zip-файл является несжимаемым, но когда он содержит много идентичных файлов, компрессор может найти эту избыточность и сжать ее. Обратите внимание, что я также видел небольшой выигрыш при работе с большим количеством файлов без избыточности. Если вы действительно заботитесь о размере, стоит попробовать, если у вас в архиве очень много файлов.

Лорен Печтель
источник
Это работает, только если вы делаете первый zip с выключенным сжатием, как я упоминал выше.
Монти Хардер
@MontyHarder Я видел, как это работает с включенным сжатием.
Лорен Печтель