Чому Zip здатний стискати один файл менше, ніж кілька файлів з одним вмістом?


126

Припустимо, у мене є 10 000 XML-файлів. Тепер припустимо, що я хочу надіслати їх другові. Перш ніж надсилати їх, я хотів би їх стиснути.

Спосіб 1. Не стискайте їх

Результати:

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

Спосіб 2: Скопіюйте кожен файл і надішліть йому 10 000 XML-файлів

Команда:

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

Результати:

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

Спосіб 3: Створіть єдиний поштовий індекс, що містить 10 000 файлів 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 Мб незрозумілого простору.


34
Якщо я не помиляюся, саме ця феномена змушує людей виготовляти, .tar.gzа не просто застібати весь каталог.
corsiKa

18
З таким запитанням вже запитав, Tl, д - р використовувати тверді 7zip архіви.
Дмитро Григор’єв

3
@sixtyfootersdude Як тест на підтвердження деяких відповідей, чи можете ви спробувати застебнути блискавку, створену у методі 3? Я підозрюю, що це зменшить розмір файлу до чогось порівнянного зі способом 4.
Тревіс

7
Замість того , щоб $(ls -1)просто використовувати *: for x in *; zip all.zip *
муру

4
Якщо ви хочете зробити суцільне стиснення за допомогою ZIP, ось такий спосіб: спочатку створіть нестиснений ZIP, який містить усі ваші файли. Потім помістіть його в інший стислий ZIP.
користувач20574

Відповіді:


129

Zip обробляє вміст кожного файлу окремо під час стискання. Кожен файл матиме власний стислий потік. Існує підтримка в алгоритмі стиснення (як правило, DEFLATE ) для ідентифікації повторних розділів. Однак у Zip немає підтримки для пошуку надмірності між файлами.

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


9
Ось чому деякі інструменти стиснення дають можливість стискати файли окремо або як єдине ціле. (Хоча це також означає, що вам доведеться розпаковувати більше архіву, ніж інакше, якщо ви хочете переглянути в ньому лише один файл.)
JAB

28
@JAB: Інструменти стиснення, такі як 7z та rar, використовують термін "твердий" архів для упаковки декількох файлів головою до хвоста у більші потоки стиснення. При помірному розмірі шматка, як 64MiB, випадковий доступ до одного файлу може зажадати декомпресії даних до 64MiB від початку блоку стиснення, який він знаходиться. Ви можете отримати гідний компроміс між випадковим доступом та знаходженням надмірності файлів. 7z може використовувати більш ефективну (але повільніше стискати) схему стиснення LZMA, що є ще однією перевагою перед zip.
Пітер Кордес

Ви хочете сказати, що there is no support in Zip to find redundancy between filesце в специфікації zip-файлу?
шістдесят футів

6
@sixtyfootersdude Багато алгоритмів стиснення, такі як DEFLATE, працюють як потік. Щоб відновити достатню кількість інформації для декомпресії частини потоку, потрібно обробити весь потік до цього моменту. Якщо вони намагаються знайти надмірність між файлами, вам доведеться розпакувати всі 1000 файлів, щоб дістатися до останнього. Це, як правило, фактично працює tgz. Однак поштовий індекс був розроблений для того, щоб ви могли витягувати окремі файли. ТГц розрахований на те, щоб бути більше, або нічого
Cort Ammon

1
@sixtyfootersdude - це правильно. Перефразовуючи Cort: Специфікації pkzip не підтримують робочий крос-файл. Якщо вони зробили, то вилучення одного файлу може вимагати вилучення всього архіву (і кожного файлу).
Джеймс Снелл

48

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

Спрощено, якщо ви стискаєте один файл, словник, який відображає (короткі) коди на (довші) шаблони, обов'язково міститься у кожному отриманому поштовому файлі; якщо ви накопичуєте один довгий файл, словник "повторно використовується" і стає ще більш ефективним для всього вмісту.

Якщо ваші файли навіть трохи схожі (як завжди текст), повторне використання «словника» стає дуже ефективним, а результат - значно меншим загальним ZIP.


3
ZIP робить і архівування, і стиснення. Чи означає це, що ZIP стискає кожен файл окремо, навіть якщо всі вони знаходяться в одному ZIP-файлі?
Герріт

2
це якось повинно - уявіть, ви видалите один файл, ви не хочете, щоб він витратив ще півгодини на повторний стиснення решти за допомогою нового "словника". - також, мабуть, передбачається, що для різних файлів потрібні дуже різні "словники".
серпня

2
Я не бачу, чому це потрібно. За допомогою інструментів Unix я б спочатку архівував файл з tar, а потім стискав його з gzip / bz2 / lzma. Алгоритм стиснення не має значення, скільки файлів закодовано в архіві. Крім того, наскільки насправді видаляти один файл із стислого архіву? Я не думаю, що я ніколи цього робив.
gerrit

4
Я не згоден, і це, мабуть, хороший спосіб. Я не розробляв і не писав ZIP. Я щойно сказав, що це робить ...
Август

16
@gerrit У нього є свої проблеми. Zip розроблений так, що дозволяє швидко отримати доступ до будь-якого файлу в архіві - спробуйте розпакувати один файл із архіву UHA 100 GiB, і ви побачите, чому вони обрали саме цей шлях. Він також розроблений для додавання - ви можете мати резервну копію та просто продовжувати додавати (або замінювати) файли за потребою. Все це є величезною підмогою при використанні архівів. Компроміс полягає в тому, що якщо ви стискаєте файли, які дуже схожі (що не все є загальним), він не може використовувати подібність, щоб зменшити розмір архіву.
Луань

43

У Zip кожен файл стискається окремо. Навпаки - «суцільне стиснення», тобто файли стискаються разом. 7-zip та Rar за замовчуванням використовують тверду компресію. Gzip і Bzip2 не можуть стискати декілька файлів, тому спочатку використовується Tar, маючи такий же ефект, як і тверде стиснення.

Оскільки файл XML має подібну структуру та, ймовірно, подібний вміст, якщо файли стиснуті разом, стиснення буде вище.

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


9

Zip не просто зберігає вміст файлу, він також зберігає метадані файлів, такі як власний ідентифікатор користувача, дозволи, час створення та модифікації тощо. Якщо у вас є один файл, у вас є один набір метаданих; якщо у вас 10 000 файлів, у вас є 10 000 наборів метаданих.


3
Хороший момент, але системні метадані займають просто 1,4 МБ місця. Дивіться мою редакцію.
шістдесят футів

1
Я не знайомий з алгоритмом zip, але метадані - це не лише інформація про файл, але також такі речі, як розмір та словник, можливо, якась інформація про розподіл символів. Словник непустого текстового файлу буде нульовим. Можливо, тому ви бачите, що метадані у ваших xml-файлах більші, ніж у ваших порожніх файлах.
Бен Річардс

Це була моя перша думка. Інформація про заголовок zip-файлів
WernerCD

Це лише пояснює різницю між 2 та 3 - не 4.
Луань

@Luaan Ні, і в 2 і 3 метадані для всіх 10000 файлів включаються в zip-файл або файли, тому загальний розмір файлу майже однаковий. У 4 є лише метадані для одного файлу, а zip-файл набагато менший.
Майк Скотт

7

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

Завдяки повсюдності безкоштовних інструментів, таких як 7-Zip, щоб розширити сімейство смол на Windows, насправді немає причин не використовувати .tar.gz або .tar.bz тощо, як це мають Linux, OS X та BSD. рідні інструменти для маніпулювання ними.


gzip та bzip2 можуть закінчитися ще гірше, оскільки вони розроблені з урахуванням потоків стиснення, тому їм доведеться починати виводити стислі дані, перш ніж всі дані для стиснення навіть будуть відомі.
rackandboneman

@rackandboneman: Це компроміс, який ви повинні зробити при стисненні файлів, більший за обсяг пам'яті, який ви готові використовувати під час стиснення. (А також, кількість часу процесора, необхідного для пошуку чого-небудь глобально оптимального, було б величезним.) Величезний словник стиснення також може збільшити обсяг пам'яті, необхідний для декомпресії . Це варіант для LZMA ( xz/ 7-zip). У будь-якому випадку, адаптивні словники можуть вибирати шаблони, коли вони помітні. Це не так, як він просто будує статичну систему кодування на основі перших 32k. Ось чому gzip не смокче.
Пітер Кордес

Мені дуже подобається цей «трюк», якщо вам потрібно залишитися у форматі zip. Я не погоджуюся з вашим "відсутністю причин не використовувати 7-zip" - якщо я надсилаю файл другові, який не є технічним, я хочу бути впевненим, що вони зможуть легко його відкрити. Якщо я надсилаю бізнес-клієнту, тим більше.
Wowfunhappy

5

Формат стиснення zip зберігає та стискає кожен файл окремо. Це не використовує повторення між файлами, лише в межах файлу.

Об’єднання файлу дозволяє zip використовувати переваги повторень у всіх файлах, що призводить до різкого стиснення.

Наприклад, скажімо, що кожен XML-файл має певний заголовок. Цей заголовок виникає лише один раз у кожному файлі, але повторюється майже однаково у багатьох інших файлах. У способах 2 і 3 блискавка не могла стиснути це, але в методі 4 вона могла.


3
Чим це відрізняється від однієї з найкращих 3 відповідей, які вже були опубліковані на 5 годин раніше?
Xen2050

1
@ Xen2050 Не велика різниця, я просто думав, що можу пояснити це більш чітко.
BonsaiOak

1
@BonsaiOak - тоді додайте коментар до правильної відповіді або відредагуйте, якщо у вас достатньо представника. Якщо ні, але ваш коментар додає ясності, хтось інший може забрати це і все-таки відредагувати публікацію.
АдамВ

@AdamV Я бачу вашу думку. Моя відповідь наразі не додає корисної інформації, хоча, мабуть, це було, коли я її писав. Під першою відповіддю вже є відповідні коментарі, тому я не бачу сенсу в їх додаванні. Ти кажеш, що я повинен просто закрити свою відповідь? Яка шкода, якщо залишити його відкритим?
BonsaiOak

4

Поруч із метаданими, про які згадував Майк Скотт, також існує алгоритм стиснення.

Стискаючи купу окремих невеликих файлів, вам доведеться пощастити, що зможете їх стиснути, що просто виходить заповнити один блок стиснення. При стисненні одного монолітного блоку система може просто продовжувати передачу даних до свого алгоритму, ігноруючи «межі» (за відсутністю кращого слова) окремих файлів.

Також відомо, що ASCII має високий коефіцієнт стиснення. плюс xml часто дуже повторюється, що робить метадані великою частиною даних, які не можна так легко стиснути, як вміст xml.

Нарешті, якщо пам'ять слугує правильно, zip використовує щось на зразок кодування словника, що особливо ефективно для файлів ascii і тим більше для XML через їх повторюваності

Пояснення стиснення даних: http://mattmahoney.net/dc/dce.html


3

Розглянемо цей XML:

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

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

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

Тепер, якщо ви об’єднаєте різні файли XML в один файл, навіть коли ці файли мають абсолютно різні імена тегів, алгоритм стиснення знайде найкращий розподіл шаблону по всіх файлах, а не файл за файлом.

Зрештою алгоритм стиснення знайшов найкращий повторний розподіл шаблону.


-1

На додаток до відповіді 7-Zip, є ще один підхід, який не так добре, але варто перевірити, якщо з якихось причин ви не хочете використовувати 7-Zip:

Стисніть zip-файл. Тепер, як правило, zip-файл нестискається, але коли він містить багато однакових файлів, компресор може знайти це надмірність і стиснути його. Зауважте, що я також бачив невеликий приріст, коли працював з великою кількістю файлів без надмірності. Якщо ви дійсно піклуєтеся про розмір, варто спробувати, якщо у вас в папері дуже багато файлів.


Це працює лише в тому випадку, якщо ви робите перший блискавку із вимкненим стисненням, як я вже згадував вище.
Monty Harder

@MontyHarder Я бачив, як це працює з увімкненою компресією.
Лорен Печтел
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.