如何壓縮多個大的、高熵的、但非常相似的檔案?

如何壓縮多個大的、高熵的、但非常相似的檔案?

我有幾個大(例如:比任何字典都大,數百 GB)檔案。這些檔案的熵非常高,壓縮效果也很差。然而,這些文件(據我所知)幾乎完全相同。 (並且實際上沒有壓縮)

作為測試用例,嘗試進行小規模模擬:

dd if=/dev/urandom of=random count=1G

cat random random random > 3random

gz -1 < 3random > 3random.gz
xz -1 < 3random > 3random.xz

我認為這很好地模擬了用我的文件打包 tar 。對於 gz 和 xz 都無法壓縮這些文件,我並不感到驚訝,事實上它們會變得稍微大一點。

有沒有一種明智的方法來壓縮這些檔案?這僅針對(離線)存檔建議,解壓縮不會經常進行。

答案1

讓我們從一個 10MB 的偽隨機資料檔案開始,並為其製作兩個副本:

$ dd if=/dev/urandom of=f1 bs=1M count=10
$ cp f1 f2
$ cp f1 f3

讓我們更改這些副本,使它們「幾乎完全相同」(正如您所說):

$   # Avoid typos and improve readability
$ alias random='od -t u4 -N 4 /dev/urandom |
  sed -n "1{s/^\S*\s//;s/\s/${fill}/g;p}"'
$ alias randomize='dd if=/dev/urandom bs=1 seek="$(
    echo "scale=0;$(random)$(random)$(random)$(random) % (1024*1024*10)" | bc -l
  )" count="$( echo "scale=0;$(random)$(random) % 512 + 1" |
    bc -l )" conv=notrunc'
$   # In files "f2" and "f3, replace 1 to 512Bytes of data with other
$   #+ pseudo-random data in a pseudo-random position. Do this 3
$   #+ times for each file
$ randomize of=f2
$ randomize of=f2
$ randomize of=f2
$ randomize of=f3
$ randomize of=f3
$ randomize of=f3

現在我們可以壓縮每個文件中的數據,看看會發生什麼:

$ xz -1 < f1 > f1.xz
$ xz -1 < f2 > f2.xz
$ xz -1 < f3 > f3.xz
$ ls -lh f{1..3}{,.xz}
-rw-rw-r-- 1 myuser mygroup 10M may 29 09:31 f1
-rw-rw-r-- 1 myuser mygroup 11M may 29 10:07 f1.xz
-rw-rw-r-- 1 myuser mygroup 10M may 29 10:00 f2
-rw-rw-r-- 1 myuser mygroup 11M may 29 10:07 f2.xz
-rw-rw-r-- 1 myuser mygroup 10M may 29 10:05 f3
-rw-rw-r-- 1 myuser mygroup 11M may 29 10:07 f3.xz

我們可以看到這實際上增加了數據的大小。現在讓我們將資料轉換為十六進位人類可讀資料(嗯,有點)並壓縮結果:

$ xxd f1 | tee f1.hex | xz -1 > f1.hex.xz
$ xxd f2 | tee f2.hex | xz -1 > f2.hex.xz
$ xxd f3 | tee f3.hex | xz -1 > f3.hex.xz
$ ls -lh f{1..3}.hex*
-rw-rw-r-- 1 myuser mygroup 42M may 29 10:03 f1.hex
-rw-rw-r-- 1 myuser mygroup 22M may 29 10:04 f1.hex.xz
-rw-rw-r-- 1 myuser mygroup 42M may 29 10:04 f2.hex
-rw-rw-r-- 1 myuser mygroup 22M may 29 10:07 f2.hex.xz
-rw-rw-r-- 1 myuser mygroup 42M may 29 10:05 f3.hex
-rw-rw-r-- 1 myuser mygroup 22M may 29 10:07 f3.hex.xz

數據變得非常大。十六進制四次,如果十六進制壓縮則兩次。現在有趣的部分:讓我們計算十六進制和壓縮之間的差異:

$ diff f{1,2}.hex | tee f1-f2.diff | xz -1 > f1-f2.diff.xz
$ diff f{1,3}.hex | tee f1-f3.diff | xz -1 > f1-f3.diff.xz
$ ls -lh f1-*
-rw-rw-r-- 1 myuser mygroup 7,8K may 29 10:04 f1-f2.diff
-rw-rw-r-- 1 myuser mygroup 4,3K may 29 10:06 f1-f2.diff.xz
-rw-rw-r-- 1 myuser mygroup 2,6K may 29 10:06 f1-f3.diff
-rw-rw-r-- 1 myuser mygroup 1,7K may 29 10:06 f1-f3.diff.xz

這很可愛。我們總結一下:

$   # All you need to save to disk is this
$ du -cb f1{,-*z}
10485760        f1
4400    f1-f2.diff.xz
1652    f1-f3.diff.xz
10491812        total
$   # This is what you would have had to store
$ du -cb f{1..3}
10485760        f1
10485760        f2
10485760        f3
31457280        total
$   # Compared to "f2"'s original size, this is the percentage
$   #+ of all the new information you need to store about it
$ echo 'scale=4; 4400 * 100 / 31457280' | bc -l
.0419
$   # Compared to "f3"'s original size, this is the percentage
$   #+ of all the new information you need to store about it
$ echo 'scale=4; 1652 * 100 / 10485760' | bc -l
.0157
$   # So, compared to the grand total, this is the percetage
$   #+ of information you need to store 
$ echo 'scale=2; 10491812 * 100 / 10485760' | bc -l
33.35

您擁有的文件越多,效果就越好。若要對「f2」的壓縮差異中的資料進行復原測試:

$ xz -d < f1-f2.diff.xz > f1-f2.diff.restored
$   # Assuming you haven't deleted "f1.diff":
$ patch -o f2.hex.restored f1.hex f1-f2.diff.restored
patching file f1.hex
$ diff f2.hex.restored f2.hex # No diffs will be found unless corrupted
$ xxd -r f2.hex.restored f2.restored # We get the completely restored file
$ diff -q f2 f2.restored # No diffs will be found unless corrupted

評論

  • 您不需要此處產生的某些文件,例如原始文件的壓縮版本和壓縮的十六進位。我做這些只是為了表明一個觀點。
  • 這種方法的成功很大程度上取決於「幾乎完全相同」的意思。你需要進行測試。我做了一些測試,這對於很多很多類型的資料(即資料庫轉儲,甚至編輯過的圖像和影片)都非常有效。我實際上用它來進行一些備份。
  • 更複雜的方法是使用 librsync,但這在許多情況下都非常有效,並且幾乎可以在任何 *nix 環境中完美運行,而無需安裝新軟體。
  • 不利的一面是,這可能需要一些腳本。
  • 我不知道有什麼工具可以完成這一切。

答案2

gzip 適用於 32Kb 區塊,因此如果相同的模式在 32Kb 範圍內(這不是您的情況),將會有所幫助。對於 xz 你可以嘗試傳遞一個非常大的--區塊大小但你需要大量的備用記憶體(請參閱--記憶體限制選項)。

相關內容