題 為什麼Zip能夠壓縮單個文件小於具有相同內容的多個文件?


假設我有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

命令:

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.4MB。這意味著仍有大約10 MB的無法解釋的空間。


121
2017-12-14 17:30


起源


如果我沒有弄錯的話,這就是導致人們製造的現象 .tar.gz 而不是只是壓縮整個目錄。 - corsiKa
一個 類似的問題 已被問過,tl; dr使用固體7zip檔案。 - Dmitry Grigoryev
@sixtyfootersdude作為驗證一些答案的測試,您可以嘗試壓縮方法3中生成的zip嗎?我懷疑這會將文件大小減少到與方法4相當的程度。 - Travis
代替 $(ls -1),只是使用 *: for x in *; zip all.zip * - muru
如果你想用ZIP進行固態壓縮,這裡有一個解決方法:首先,創建一個 未壓縮 包含所有文件的ZIP。然後,將該ZIP放入另一個壓縮的ZIP中。 - user20574


答案:


壓縮時Zip會單獨處理每個文件的內容。每個文件都有自己的壓縮流。壓縮算法中有支持(通常 DEFLATE)識別重複的部分。但是,Zip中沒有支持查找文件之間的冗餘。

這就是當內容在多個文件中時有太多額外空間的原因:它將多個相同的壓縮流放在文件中。


126
2017-12-14 19:24



這也是為什麼一些壓縮工具可以選擇單獨壓縮文件或作為單個實體壓縮文件。 (儘管通常這也意味著你必須解壓縮更多的存檔而不是你想要查看其中的單個文件。) - JAB
@JAB:像7z和rar這樣的壓縮工具使用術語“實體”存檔將多個文件打包成大型壓縮流。對於像64MiB這樣的中等塊大小,隨機訪問單個文件可能需要從壓縮塊的開頭解壓縮多達64MiB的數據。您可以在隨機訪問和查找跨文件冗餘之間進行適當的權衡。 7z可以使用更有效(但壓縮更慢)的LZMA壓縮方案,這是另一個優於zip的優勢。 - Peter Cordes
你是這麼說的嗎? there is no support in Zip to find redundancy between files 在zip文件規範中? - sixtyfootersdude
@sixtyfootersdude許多壓縮算法(如DEFLATE)作為流運行。要恢復足夠的信息以解壓縮部分流,您需要處理整個流直到該點。如果他們試圖找到文件之間的冗餘,你必須解壓縮所有1000個文件才能到達最後一個文件。實際上,這通常是tgz的工作原理。但是,zip旨在讓您提取單個文件。 tgz旨在更多全有或全無 - Cort Ammon
@sixtyfootersdude - 這是正確的。解釋Cort:pkzip規範不支持工作交叉文件。如果他們這樣做,那麼提取一個文件可能需要提取整個存檔(和每個文件)。 - James Snell


ZIP壓縮基於要壓縮的數據中的重複模式,並且隨著可以找到和使用越來越多的模式,壓縮隨著文件越長越好。

簡而言之,如果您壓縮一個文件,那麼將(短)代碼映射到(更長)模式的字典必然包含在每個生成的zip文件中;如果您壓縮一個長文件,字典將被“重複使用”,並且在所有內容中變得更加有效。

如果你的文件甚至有點類似(總是文本),重複使用'字典'變得非常有效,結果是總拉鍊小得多。


47
2017-12-14 18:48



ZIP同時進行歸檔和壓縮。這是否意味著ZIP會單獨壓縮每個文件,即使它們最終都在同一個ZIP文件中? - gerrit
它有點必須 - 想像你刪除一個文件,你不會希望它再花半小時用新的'字典'重新壓縮其餘的文件。 - 此外,它可能假設不同的文件需要非常不同的“詞典”。 - Aganju
我不明白為什麼要這樣做。使用Unix工具,我首先使用tar歸檔文件,然後使用gzip / bz2 / lzma壓縮它。壓縮算法不關心歸檔中編碼的文件數量。另外,從壓縮存檔中刪除單個文件有多常見?我不認為我曾經那樣做過。 - gerrit
我不反對,這可能是一個好方法。我沒有設計或寫ZIP。我只是說它做了什麼...... - Aganju
@gerrit它有自己的問題。 Zip旨在允許您快速訪問存檔中的任何文件 - 嘗試從100 GiB UHA存檔中解壓縮單個文件,您將看到他們選擇這種方式的原因。它也是為追加而設計的 - 您可以擁有備份zip,並根據需要不斷添加(或替換)文件。所有這些在使用檔案時都是一個巨大的幫助。權衡的是,如果你正在壓縮非常相似的文件(即 不 所有這些常見的),它無法利用相似性來減少存檔大小。 - Luaan


在Zip中,每個文件都是單獨壓縮的。相反的是“固體壓縮”,即文件被壓縮在一起。 7-zip和Rar默認使用固態壓縮。 Gzip和Bzip2無法壓縮多個文件,因此首先使用Tar,與固體壓縮具有相同的效果。

由於xml文件具有相似的結構,並且如果文件被壓縮在一起可能具有相似的內容,則壓縮將更高。

例如,如果文件包含字符串 "<content><element name=" 並且壓縮器已經在另一個文件中找到該字符串,它將用一個指向前一個匹配的小指針替換它,如果壓縮器不使用“固態壓縮”,則文件中字符串的第一個出現將被記錄為文字更大


42
2017-12-14 20:02





Zip不僅存儲文件的內容,還存儲文件元數據,如擁有用戶ID,權限,創建和修改時間等。如果你有一個文件,你有一組元數據;如果您有10,000個文件,則擁有10,000組元數據。


9
2017-12-14 17:38



好點,但係統元數據只佔用1.4MB的空間。看我的編輯。 - sixtyfootersdude
我不熟悉zip算法,但元數據不僅僅是文件信息,還有大小和字典之類的東西,可能還有一些關於字符分佈的信息。非空文本文件上的字典將為非零。這可能就是為什麼你看到xml文件中的元數據比空文件大。 - Ben Richards
這是我的第一個念頭。 Zip-File標頭信息 - WernerCD
這只能解釋2和3之間的區別 - 而不是4。 - Luaan
@Luaan不,在2和3中,所有10,000個文件的元數據都包含在zip文件或文件中,因此總文件大小幾乎相同。在4中,只有一個文件的元數據,而zip文件要小得多。 - Mike Scott


OP錯過的一個選項是在關閉壓縮的情況下將所有文件壓縮,然後將壓縮設置為最大壓縮拉鍊。這大致模擬了* nix .tar.Z,.tar.gz,.tar.bz等壓縮存檔的行為,允許壓縮利用跨文件邊界的冗餘(ZIP算法在單個運行時無法執行通過)。這允許稍後提取單個XML文件,但最大化壓縮。缺點是提取過程需要額外的步驟,暫時使用比正常.zip所需的更多的磁盤空間。

隨著無處不在的免費工具(如7-Zip)將tar系列擴展到Windows,沒有理由不使用.tar.gz或.tar.bz等,因為Linux,OS X和BSD都有用於操縱它們的本機工具。


6
2017-12-15 15:50



gzip和bzip2可能會更糟糕,因為它們的設計考慮了壓縮流,因此在壓縮所有要壓縮的數據之前,它們必須開始輸出壓縮數據。 - rackandboneman
@rackandboneman:這是壓縮文件時必須做出的權衡,這些文件大於你在壓縮時願意使用的內存量。 (而且,查找全局優化所需的CPU時間量將是巨大的。)一個巨大的壓縮字典也可以增加所需的內存 減壓。這是LZMA的一個選項(xz / 7-zip)。無論如何,自適應詞典一旦可見就可以獲取模式。它不僅僅是建立一個基於前32k的靜態編碼系統。這就是為什麼gzip不會吮吸的原因。 - Peter Cordes


zip壓縮格式分別存儲和壓縮每個文件。它不利用文件之間的重複,僅在文件中重複。

連接文件允許zip利用所有文件的重複,從而大大提高壓縮率。

例如,假設每個XML文件都有一個標題。該標題僅在每個文件中出現一次,但在許多其他文件中幾乎完全相同。在方法2和3中,zip不能為此壓縮,但在方法4中它可以。


5
2017-12-15 01:19



這與5小時前發布的前三個答案之一有什麼不同? - Xen2050
@ Xen2050沒什麼區別,我只是覺得我可以更清楚地解釋一下。 - BonsaiOak
@BonsaiOak - 然後在正確的答案中添加評論或編輯,如果你有足夠的代表。如果沒有,但你的評論增加了清晰度,其他人可能會選擇這個並編輯帖子。 - AdamV
@AdamV我明白你的意思了。我的答案目前沒有添加任何有用的信息,儘管它可以說是我寫的時候。在第一個答案下已有適當的評論,所以我也沒有看到添加它們的重點。你是說我應該關閉我的答案嗎?讓它開放有什麼危害? - BonsaiOak


在Mike Scott提到的元數據旁邊,壓縮算法也存在開銷。

當壓縮一堆單獨的小文件時,你必須非常幸運能夠壓縮它們才恰好填充一個壓縮塊。 壓縮單個整體塊時,系統可以繼續將數據流式傳輸到其算法,忽略單個文件的“邊界”(缺少更好的單詞)。

還已知ASCII具有高壓縮因子。加上xml通常非常重複,使得元數據成為很大一部分數據,不能像xml內容那樣輕易壓縮。

最後,如果內存服務正確,zip使用字典編碼之類的東西,這對ascii文件特別有效,而且由於它們的重複性而更加依賴於XML

數據壓縮說明: http://mattmahoney.net/dc/dce.html


4
2017-12-14 18:02





考慮這個XML:

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

XML具有非常重複的結構,Zip利用這些重複來構建其中的字典 圖案 有更多的出現,然後,當壓縮時,使用較少的位來存儲更多的重複 模式 和更多的比特來存儲較少的重複 圖案

當你 串聯 那些文件,源文件(zip的來源)很大,但包含更多 重複的模式 因為XML的無聊結構的分佈是 攤銷 在整個大文件中,有機會ZIP存儲這些 圖案 使用較少的位。

現在,如果將不同的XML組合到單個文件中,即使這些文件具有完全不同的標記名稱,壓縮算法也會發現最佳 圖案跨所有文件分發,而不是逐個文件。

最終,壓縮算法找到了最佳的重複模式分佈。


3
2017-12-16 01:27