我只是做了一個小實驗,我創建了一個包含重複檔案的 tar 存檔,看看它是否會被壓縮,令我驚訝的是,它沒有被壓縮!詳細資訊如下(結果縮排以方便閱讀):
$ dd if=/dev/urandom bs=1M count=1 of=a
1+0 records in
1+0 records out
1048576 bytes (1.0 MB) copied, 0.114354 s, 9.2 MB/s
$ cp a b
$ ln a c
$ ll
total 3072
-rw-r--r-- 2 guido guido 1048576 Sep 24 15:51 a
-rw-r--r-- 1 guido guido 1048576 Sep 24 15:51 b
-rw-r--r-- 2 guido guido 1048576 Sep 24 15:51 c
$ tar -c * -f test.tar
$ ls -l test.tar
-rw-r--r-- 1 guido guido 2109440 Sep 24 15:51 test.tar
$ gzip test.tar
$ ls -l test.tar.gz
-rw-r--r-- 1 guido guido 2097921 Sep 24 15:51 test.tar.gz
$
首先,我創建了一個 1MiB 的隨機資料檔 (a)。然後我將其複製到文件 b 並將其連結到 c。創建 tarball 時,tar 顯然知道硬鏈接,因為 tarball 只有 ~2MiB 而不是 ~3Mib。
現在我期望 gzip 將 tarball 的大小減少到 ~1MiB,因為 a 和 b 是重複的,而 tarball 內應該有 1MiB 的連續資料重複,但這並沒有發生。
為什麼是這樣?在這些情況下如何有效地壓縮 tarball?
答案1
Gzip gzip 是基於 DEFLATE 演算法,該演算法是 LZ77 和 Huffman 編碼的結合。它是一種無損資料壓縮演算法,其工作原理是使用動態建構的字典將輸入流轉換為壓縮符號並監視重複項。但它無法找到間隔超過 32K 的重複項。期望它能夠發現相隔 1MB 的重複項是不切實際的。
答案2
妮可·漢密爾頓正確地註意到gzip
由於字典大小較小,因此不會找到遙遠的重複資料。
bzip2
類似,因為它的記憶體限制為 900 KB。
相反,請嘗試:
LZMA/LZMA2 演算法 ( xz
, 7z
)
LZMA 演算法與 Deflate 屬於同一系列,但使用更大的字典大小(可自訂;預設值約為 384 MB)。該xz
實用程式應預設安裝在最新的 Linux 發行版上,它與 LZMA 類似gzip
並使用 LZMA。
當 LZMA 偵測到更遠距離的冗餘時,它將能夠在此處對您的資料進行重複資料刪除。然而,它比 Gzip 慢。
另一個選項是 7-zip(7z
在套件中p7zip
),它是一個預設使用 LZMA 的歸檔器(而不是單流壓縮器)(由 LZMA 的作者編寫)。 7-zip 歸檔程式在歸檔為其格式時,會在檔案層級執行自己的重複資料刪除(查看具有相同副檔名的檔案).7z
。這意味著,如果您願意替換tar
為7z
,您將獲得重複資料刪除的相同檔案。但是,7z 不保留納秒時間戳記、權限或 xattrs,因此它可能不適合您的需求。
lrzip
lrzip
是一種壓縮器,可在將資料輸入 Gzip/Deflate、bzip2、lzop 或 LZMA 等傳統演算法之前對資料進行預處理以消除長距離冗餘。對於您在此處提供的範例數據,沒有必要;當輸入資料大於記憶體所能容納的資料時,它非常有用。
對於這種類型的資料(重複的不可壓縮區塊),您應該使用lzop
壓縮(非常快)lrzip
,因為一旦進行重複資料刪除,再努力壓縮完全隨機的資料就沒有任何好處。
布普和奧布南
答案3
gzip
不會找到重複項,即使xz
字典大小很大也不會。你能做的就是使用mksquashfs
- 這確實會節省重複的空間。
xz
使用三個隨機二進位(64MB)進行一些快速測試結果,mksquashfs
其中兩個是相同的:
設定:
mkdir test
cd test
dd if=/dev/urandom of=test1.bin count=64k bs=1k
dd if=/dev/urandom of=test2.bin count=64k bs=1k
cp test{2,3}.bin
cd ..
南瓜:
mksquashfs test/ test.squash
> test.squash - 129M
xz:
XZ_OPT='-v --memlimit-compress=6G --memlimit-decompress=512M --lzma2=preset=9e,dict=512M --extreme -T4 ' tar -cJvf test.tar.xz test/
> test.tar.xz - 193M
答案4
作為“機械蝸牛”答案的補充:
如果未壓縮的單一檔案的檔案大小(或更準確地說,重複項之間的距離)超過字典大小,則即使 xz(或 lzma)也找不到重複項。 xz(或 lzma)即使在最高設定下也-9e
僅為此保留 64MB。
幸運的是,您可以使用選項指定您自己的字典大小--lzma2=dict=256MB
(僅--lzma1=dict=256MB
在使用命令的 lzma 別名時才允許)
不幸的是,當使用上面範例中給出的自訂壓縮鏈覆蓋設定時,所有其他參數的預設值不會設定為與 -9e 相同的等級。因此單一檔案的壓縮密度沒有那麼高。