Wie komprimiert man mehrere große, aber sehr ähnliche Dateien mit hoher Entropie?

Wie komprimiert man mehrere große, aber sehr ähnliche Dateien mit hoher Entropie?

Ich habe mehrere große (also: größer als jedes Wörterbuch, Hunderte von GB) Dateien. Diese Dateien haben eine sehr hohe Entropie und lassen sich sehr schlecht komprimieren. Allerdings sind diese Dateien (soweit ich das beurteilen kann) fast völlig identisch. (Und nicht wirklich komprimiert)

Als Testfall habe ich eine Simulation im kleinen Maßstab versucht:

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

cat random random random > 3random

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

Ich denke, dies simuliert das Packen eines Tar mit meinen Dateien ganz gut. Es überrascht mich nicht, dass weder gz noch xz diese Dateien komprimieren können, tatsächlich werden sie etwas größer.

Gibt es eine sinnvolle Möglichkeit, diese Dateien zu komprimieren? Dies ist nur für (Offline-)Archivzwecke gedacht, das Dekomprimieren wird nicht häufig durchgeführt.

Antwort1

Beginnen wir mit einer 10 MB großen Datei pseudozufälliger Daten und erstellen zwei Kopien davon:

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

Lassen Sie uns diese Kopien so ändern, dass sie „fast völlig identisch“ sind (wie Sie sagten):

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

Jetzt können wir die Daten in jeder Datei komprimieren, um zu sehen, was passiert:

$ 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

Wir können sehen, dass dies die Datengröße tatsächlich erhöht. Lassen Sie uns nun die Daten in hexadezimale, für Menschen lesbare Daten umwandeln (na ja, so ungefähr) und das Ergebnis komprimieren:

$ 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

Die Daten sind wirklich groß geworden. Viermal in Hex, zweimal, wenn Hex komprimiert ist. Jetzt kommt der spaßige Teil: Berechnen wir die Differenz zwischen dem Hex und dem komprimierten:

$ 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

Und das ist schön. Fassen wir zusammen:

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

Je mehr Dateien Sie haben, desto besser funktioniert dies. So führen Sie einen Wiederherstellungstest der Daten aus Ihren komprimierten Diffs von „f2“ durch:

$ 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

BEMERKUNGEN

  • Manche der hier generierten Dateien, wie die komprimierten Versionen der Originaldateien und die komprimierten Hex-Dateien, benötigen Sie nicht. Ich habe sie nur erstellt, um etwas klarzustellen.
  • Der Erfolg dieser Methode hängt stark von der Bedeutung von „fast völlig identisch“ ab. Sie müssen Tests durchführen. Ich habe einige Tests durchgeführt und dies funktioniert hervorragend für viele, viele Datentypen (nämlich Datenbank-Dumps und sogar bearbeitete Bilder und Videos). Ich verwende dies tatsächlich für einige Backups.
  • Eine ausgefeiltere Methode ist die Verwendung von librsync, die jedoch in vielen Situationen hervorragend funktioniert und in fast jeder *nix-Umgebung perfekt funktioniert, ohne dass neue Software installiert werden muss.
  • Der Nachteil hierbei ist, dass hierfür möglicherweise einige Skripts erforderlich sind.
  • Ich kenne kein Tool, das das alles kann.

Antwort2

gzip arbeitet mit 32Kb-Blöcken, daher wäre es hilfreich, wenn die gleichen Muster in einem 32Kb-Bereich liegen (was bei Ihnen nicht der Fall ist). Für xz könnten Sie versuchen, eine sehr große--Block Größeaber Sie brauchen viel freien Speicher (siehe--memlimitOptionen).

verwandte Informationen