Perché Zip è in grado di comprimere un singolo file più piccolo di più file con lo stesso contenuto?


126

Supponiamo che io abbia 10.000 file XML. Ora supponiamo che io voglia inviarli a un amico. Prima di inviarli, vorrei comprimerli.

Metodo 1: non comprimerli

risultati:

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

Metodo 2: comprimere ogni file e inviargli 10.000 file XML

Comando:

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

risultati:

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

Metodo 3: creare un singolo zip contenente 10.000 file XML

Comando:

zip all.zip $(ls -1)

risultati:

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

Metodo 4: concatenare i file in un singolo file e comprimerlo

Comando:

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

risultati:

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

Domande:

  • Perché ottengo risultati così incredibilmente migliori quando sto solo comprimendo un singolo file?
  • Mi aspettavo di ottenere risultati drasticamente migliori usando il metodo 3 rispetto al metodo 2, ma non farlo. Perché?
  • Questo comportamento è specifico zip? Se provassi a utilizzare gzipotterrei risultati diversi?

Informazioni addizionali:

$ 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)

Modifica: metadati

Una risposta suggerisce che la differenza sono i metadati di sistema memorizzati nella zip. Non penso che questo possa essere il caso. Per testare, ho fatto quanto segue:

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

La zip risultante è 1,4 MB. Ciò significa che ci sono ancora ~ 10 MB di spazio inspiegabile.


34
Se non sbaglio, è questo fenomeno che fa sì che le persone facciano .tar.gzinvece di comprimere l'intera directory.
corsiKa

18
Una domanda simile era già stata posta, per usare un solido archivio 7zip.
Dmitry Grigoryev,

3
@sixtyfootersdude Come test per convalidare alcune delle risposte, puoi provare a zippare la zip prodotta nel metodo 3? Sospetto che questo ridurrà la dimensione del file a qualcosa di paragonabile al metodo 4.
Travis

7
Invece di $(ls -1), basta usare *: for x in *; zip all.zip *
Muru,

4
Se vuoi fare una compressione solida con ZIP, ecco una soluzione alternativa: prima crea un ZIP non compresso contenente tutti i tuoi file. Quindi, inserisci lo ZIP in un altro ZIP compresso.
user20574

Risposte:


129

Zip tratta i contenuti di ciascun file separatamente durante la compressione. Ogni file avrà il proprio flusso compresso. Nell'algoritmo di compressione è supportato (in genere DEFLATE ) per identificare sezioni ripetute. Tuttavia, non esiste alcun supporto in Zip per trovare la ridondanza tra i file.

Ecco perché c'è così tanto spazio in più quando il contenuto si trova in più file: inserisce più volte lo stesso flusso compresso nel file.


9
È anche il motivo per cui alcuni strumenti di compressione offrono la possibilità di comprimere i file separatamente o come singola entità. (Anche se in genere ciò significa anche che devi decomprimere più archivi di quanto non faresti altrimenti se vuoi visualizzare solo un singolo file in esso.)
JAB

28
@JAB: strumenti di compressione come 7z e rar usano il termine "archivio solido" per impacchettare più file dalla coda ai flussi di compressione più grandi. Con una dimensione di blocco moderata come 64 MiB, l'accesso casuale a un singolo file potrebbe richiedere la decompressione fino a 64 MiB di dati dall'inizio del blocco di compressione in cui si trova. È possibile ottenere un discreto compromesso tra l'accesso casuale e la ricerca di ridondanza tra file. 7z può utilizzare lo schema di compressione LZMA più efficace (ma più lento da comprimere), che è un altro vantaggio rispetto a zip.
Peter Cordes,

Stai dicendo che there is no support in Zip to find redundancy between filesè nelle specifiche del file zip?
sixtyfootersdude,

6
@sixtyfootersdude Molti algoritmi di compressione, come DEFLATE, funzionano come un flusso. Per recuperare informazioni sufficienti per decomprimere una parte del flusso, è necessario elaborare l'intero flusso fino a quel punto. Se tentassero di trovare la ridondanza tra i file, dovresti decomprimere tutti i 1000 file per arrivare all'ultimo. Questo è in genere il modo in cui funziona tgz, in realtà. Tuttavia, zip è stato progettato per consentire di estrarre singoli file. tgz è progettato per essere più o meno
Cort Ammon,

1
@sixtyfootersdude - è corretto. Per parafrasare Cort: le specifiche di pkzip non supportano il funzionamento di più file. In caso contrario, l'estrazione di un file potrebbe richiedere l'estrazione dell'intero archivio (e di tutti i file).
James Snell,

48

La compressione ZIP si basa su schemi ripetitivi nei dati da comprimere e la compressione migliora quanto più lungo è il file, in quanto è possibile trovare e utilizzare modelli sempre più lunghi.

Semplificato, se comprimi un file, il dizionario che mappa i codici (brevi) su modelli (più lunghi) è necessariamente contenuto in ogni file zip risultante; se comprimi un file lungo, il dizionario viene "riutilizzato" e diventa ancora più efficace su tutto il contenuto.

Se i tuoi file sono anche un po 'simili (come sempre è il testo), il riutilizzo del' dizionario 'diventa molto efficiente e il risultato è uno zip totale molto più piccolo.


3
ZIP esegue sia l'archiviazione che la compressione. Questo significa che ZIP comprime ogni file singolarmente, anche se tutti finiscono nello stesso file ZIP?
Gerrit,

2
è un po 'necessario: immagina di rimuovere un singolo file, non vorrai che trascorra un'altra mezz'ora a comprimere il resto con un nuovo "dizionario". - inoltre, presume probabilmente che file diversi necessitino di "dizionari" molto diversi.
Aganju,

2
Non vedo perché debba. Con gli strumenti Unix, prima archiverei un file con tar, quindi lo comprimo con gzip / bz2 / lzma. L'algoritmo di compressione non importa quanti file sono codificati nell'archivio. Inoltre, quanto è comune rimuovere un singolo file da un archivio compresso? Non credo di averlo mai fatto.
Gerrit,

4
Non sono in disaccordo, e questo è probabilmente un buon modo. Non ho progettato o scritto ZIP. Ho appena detto cosa fa ...
Aganju,

16
@gerrit Ha i suoi problemi. Zip è progettato per consentirti di accedere rapidamente a qualsiasi file nell'archivio: prova a decomprimere un singolo file da un archivio UHA da 100 GiB e vedrai perché hanno scelto in questo modo. È progettato anche per l'aggiunta: puoi avere il tuo zip di backup e continuare ad aggiungere (o sostituire) i file secondo necessità. Tutto questo è di grande aiuto quando si usano gli archivi. Il compromesso è che se stai comprimendo file molto simili (che non è poi così comune), non può sfruttare le somiglianze per ridurre le dimensioni dell'archivio.
Luaan,

43

In Zip ogni file è compresso separatamente. Il contrario è la "compressione solida", ovvero i file vengono compressi insieme. 7-zip e Rar utilizzano una compressione solida per impostazione predefinita. Gzip e Bzip2 non possono comprimere più file, quindi Tar viene usato per primo, con lo stesso effetto della compressione solida.

Poiché il file xml ha una struttura simile e probabilmente un contenuto simile se i file vengono compressi insieme, la compressione sarà maggiore.

Ad esempio, se un file contiene la stringa "<content><element name="e il compressore ha già trovato quella stringa in un altro file, la sostituirà con un piccolo puntatore alla corrispondenza precedente, se il compressore non utilizza la "compressione solida" la prima occorrenza della stringa nel il file verrà registrato come un valore letterale più grande.


9

Zip non memorizza solo il contenuto del file, ma memorizza anche i metadati del file come l'ID utente proprietario, i permessi, i tempi di creazione e modifica e così via. Se hai un file hai un set di metadati; se hai 10.000 file hai 10.000 set di metadati.


3
Un buon punto, ma i metadati di sistema occupano solo 1,4 MB di spazio. Vedi la mia modifica.
sixtyfootersdude,

1
Non ho familiarità con l'algoritmo zip, ma i metadati non sono solo le informazioni sul file, ma anche cose come dimensioni e un dizionario, forse alcune informazioni sulla distribuzione dei caratteri. Un dizionario su un file di testo non vuoto sarà diverso da zero. Questo è probabilmente il motivo per cui vedi i metadati essere più grandi nei tuoi file XML rispetto ai tuoi file vuoti.
Ben Richards,

Questo è stato il mio primo pensiero. Informazioni
sull'intestazione del

Questo spiega solo la differenza tra 2 e 3 - non 4.
Luaan il

@Luaan No, in entrambi i 2 e 3 i metadati per tutti i 10.000 file sono inclusi nel file zip o nei file, quindi la dimensione totale del file è quasi della stessa dimensione. In 4, ci sono solo metadati per un file e il file zip è molto più piccolo.
Mike Scott,

7

Un'opzione mancata dall'OP è di comprimere tutti i file con la compressione disattivata, quindi comprimere lo zip risultante con la compressione impostata al massimo. Questo emula approssimativamente il comportamento degli archivi compressi * nix .tar.Z, .tar.gz, .tar.bz, ecc., Consentendo alla compressione di sfruttare le ridondanze attraverso i confini dei file (che l'algoritmo ZIP non può eseguire quando eseguito in un singolo passaggio). Ciò consente di estrarre i singoli file XML in un secondo momento, ma massimizza la compressione. Il rovescio della medaglia è che il processo di estrazione richiede il passaggio aggiuntivo, utilizzando temporaneamente molto più spazio su disco di quanto sarebbe necessario per un normale .zip.

Con l'ubiquità di strumenti gratuiti come 7-Zip per estendere la famiglia tar a Windows, non c'è davvero motivo di non usare un .tar.gz o .tar.bz, ecc., Come hanno tutti Linux, OS X e BSD strumenti nativi per manipolarli.


gzip e bzip2 potrebbero finire anche peggio perché sono progettati pensando ai flussi di compressione, quindi dovranno iniziare a produrre i dati compressi prima ancora che tutti i dati da comprimere siano noti.
Rackandboneman,

@rackandboneman: questo è il compromesso che devi fare quando comprimi file più grandi della quantità di memoria che sei disposto a usare al momento della compressione. (E inoltre, la quantità di tempo della CPU necessaria per trovare qualcosa di ottimale a livello globale sarebbe enorme.) Un enorme dizionario di compressione può anche aumentare la memoria richiesta per la decompressione . Questa è un'opzione per LZMA ( xz/ 7-zip). Ad ogni modo, i dizionari adattivi possono riprendere gli schemi una volta che sono visibili. Non è che costruisce solo un sistema di codifica statico basato sul primo 32k. Questo è il motivo per cui gzip non fa schifo.
Peter Cordes,

Mi piace molto questo "trucco" se hai bisogno di rimanere nel formato zip. Non sono d'accordo con il tuo "nessun motivo per non usare 7-zip" —se sto inviando un file a un amico non tecnico, voglio essere sicuro che saranno in grado di aprirlo facilmente. Se invio a un cliente business, anche di più.
Wowfunhappy,

5

Il formato di compressione zip archivia e comprime ogni file separatamente. Non sfrutta la ripetizione tra file, solo all'interno di un file.

La concatenazione del file consente a zip di sfruttare le ripetizioni su tutti i file, garantendo una compressione drasticamente maggiore.

Ad esempio, supponiamo che ogni file XML abbia una determinata intestazione. Tale intestazione si verifica solo una volta in ciascun file ma si ripete quasi identicamente in molti altri file. Nei metodi 2 e 3 zip non poteva comprimere per questo, ma nel metodo 4 poteva.


3
In che modo differisce da una delle prime 3 risposte già pubblicate 5 ore prima?
Xen2050,

1
@ Xen2050 Non molta differenza, pensavo solo di poterlo spiegare più chiaramente.
BonsaiOak,

1
@BonsaiOak - quindi aggiungi un commento alla risposta corretta o modifica se hai abbastanza rappresentante. In caso contrario, ma il tuo commento aggiunge chiarezza, qualcun altro potrebbe raccoglierlo e modificare comunque il post.
AdamV,

@AdamV Vedo il tuo punto. Al momento la mia risposta non aggiunge alcuna informazione utile, anche se probabilmente l'ho fatta quando l'ho scritta. Ci sono già commenti appropriati sotto la prima risposta, quindi non vedo nemmeno il punto di aggiungerli. Stai dicendo che dovrei chiudere la mia risposta? Che male c'è a lasciarlo aperto?
BonsaiOak,

4

Accanto ai metadati citati da Mike Scott c'è anche un sovraccarico nell'algoritmo di compressione.

Quando comprimi un gruppo di singoli piccoli file, dovrai essere molto fortunato a comprimere il fatto che è sufficiente riempire un blocco di compressione. Quando si comprime un singolo blocco monolitico, il sistema può semplicemente continuare a trasmettere i dati al suo algoritmo, ignorando i "limiti" (per mancanza di parole migliori) dei singoli file.

Anche ASCII è noto per avere un alto fattore di compressione. inoltre xml è spesso molto ripetitivo rendendo i metadati una grande porzione di dati che non possono essere compressi così facilmente come il contenuto xml.

Infine, se la memoria funziona bene, zip usa qualcosa come la codifica del dizionario, che è particolarmente efficace sui file ASCII e ancora di più su XML a causa della loro ripetitività

Spiegazione della compressione dei dati: http://mattmahoney.net/dc/dce.html


3

Considera questo XML:

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

Un XML ha una struttura molto ripetitivo, Zip sfrutta tali ripetizioni per costruire un dizionario di che modello ha più occorrenze e poi, quando la compressione, utilizza meno bit per memorizzare più utilizzate modelli e più bit per memorizzare meno ripetuto modello .

Quando si concatenare i file, il file sorgente (la fonte per zip) è grande, ma contiene molto di più schemi ripetuti a causa de la distribuzione delle strutture noiosi di un XML vengono ammortizzati nel grande intero file, dando la possibilità di zip per riporre coloro modello usando meno bit.

Ora, se si combinano XML diversi in un singolo file, anche quando quei file hanno nomi di tag completamente diversi, l'algoritmo di compressione troverà la migliore distribuzione di pattern su tutti i file e non file per file.

Alla fine l'algoritmo di compressione ha trovato la migliore distribuzione ripetuta dei pattern.


-1

Oltre alla risposta 7-Zip c'è un altro approccio che non è buono ma varrebbe la pena testare se per qualche motivo non vuoi usare 7-Zip:

Comprimi il file zip. Ora, normalmente un file zip è incomprimibile ma quando contiene molti file identici il compressore può trovare questa ridondanza e comprimerlo. Notare che ho anche riscontrato un piccolo guadagno quando ho a che fare con un numero elevato di file senza ridondanza. Se ti interessa davvero la dimensione, vale la pena provare se hai molti file nella tua zip.


Funziona solo se esegui la prima zip con la compressione disattivata, come ho detto sopra.
Monty Harder,

@MontyHarder L'ho visto funzionare con la compressione attivata.
Loren Pechtel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.