Diff von zwei ähnlichen großen rohen Binärdateien

Nehmen wir an, ich habe eine 4-GB-Datei abc auf meinem lokaler Computer. Ich habe es über SFTP auf einen entfernten Server hochgeladen. Es hat einige Stunden gedauert.

Jetzt habe ich die Datei lokal geringfügig geändert (wahrscheinlich maximal 50 MB, aber keine aufeinander folgenden Bytes in dieser Datei). und speicherte es in abc2. Ich habe auch die Originaldatei abc auf meinem lokalen Computer gespeichert.

Wie berechnet man einen binären Diff von abc und abc2?

Anwendungen:

  • Ich konnte nur eine patch -Datei (wahrscheinlich max. 100 MB) an senden der entfernte Server, anstatt die gesamte abc2 -Datei erneut hochzuladen (es würde wieder einige Stunden dauern!) und abc2 auf dem entfernten Server neu zu erstellen Server nur von abc und patch.

  • Lokal konnte ich nur 8 GB speichern, anstatt 8 GB für die Sicherung von abc und abc2 zu verschwenden abc + patch, daher würde < nur 4100 MB benötigt.

Wie geht das?

PS: Für Text kenne ich diff, aber hier suche ich Etwas, das für jedes rohe Binärformat funktionieren könnte, es könnte Zip-Dateien oder ausführbare Dateien oder sogar andere Dateitypen sein.

PS2: Wenn möglich, möchte ich ; Ich weiß, dass es Änderungen zwischen zwei Computern auf effiziente Weise replizieren kann (keine Daten erneut senden, die sich nicht geändert haben), aber hier möchte ich wirklich eine patch -Datei haben, die später reproduzierbar ist, wenn Ich habe sowohl abc als auch patch.

Antwort

Für die zweite Anwendung / Ausgabe würde ich ein deduplizierendes Sicherungsprogramm wie restic oder borgbackup verwenden, anstatt es zu versuchen um „Patches“ oder Diffs manuell zu verfolgen. Mit dem Sicherungsprogramm restic können Sie Verzeichnisse von mehreren Computern in demselben Sicherungsrepository sichern und die Sicherungsdaten sowohl zwischen Dateifragmenten eines einzelnen Computers als auch zwischen Computern deduplizieren. (Ich habe keine Benutzererfahrung mit borgbackup, daher kann ich nichts über dieses Programm sagen.)

Berechnen und Speichern eines Unterschieds der abc und abc2 Dateien können mit rsync erstellt werden.

Dies ist ein Beispiel mit abc und abc2 von 153 MB. Die Datei abc2 wurde durch Überschreiben von geändert erste 2,3 MB der Datei mit einigen anderen Daten:

 $ ls -lh total 626208 -rw-r--r-- 1 kk wheel 153M Feb 3 16:55 abc -rw-r--r-- 1 kk wheel 153M Feb 3 17:02 abc2  

Wir erstellen Patch zum Transformieren von abc in abc2 und nennen Sie es abc-diff:

 $ rsync --only-write-batch=abc-diff abc2 abc  
 $ ls -lh total 631026 -rw-r--r-- 1 kk wheel 153M Feb 3 16:55 abc -rw------- 1 kk wheel 2.3M Feb 3 17:03 abc-diff -rwx------ 1 kk wheel 38B Feb 3 17:03 abc-diff.sh -rw-r--r-- 1 kk wheel 153M Feb 3 17:02 abc2  

Die generierte Datei abc-diff ist der tatsächliche Unterschied (Ihre „Patch-Datei“), während abc-diff.sh istEin kurzes Shell-Skript, das rsync für Sie erstellt:

 $ cat abc-diff.sh rsync --read-batch=abc-diff ${1:-abc}  

Dieses Skript ändert abc so, dass es angesichts der Datei iv id = „f91b090ab2 mit abc2 identisch wird „>

:

 $ md5sum abc abc2 be00efe0a7a7d3b793e70e466cbc53c6 abc 3decbde2d3a87f3d954ccee9d60f249b abc2 $ sh abc-diff.sh $ md5sum abc abc2 3decbde2d3a87f3d954ccee9d60f249b abc 3decbde2d3a87f3d954ccee9d60f249b abc2  

Die Datei abc-diff kann jetzt an eine andere Stelle übertragen werden, an der Sie abc haben. Mit dem Befehl rsync --read-batch=abc-diff abc würden Sie den Patch auf die Datei abc anwenden und ihren Inhalt so umwandeln, dass er dem von abc2 -Datei auf dem System, auf dem Sie den Diff erstellt haben.

Das erneute Anwenden des Patches ein zweites Mal scheint sicher. Es gibt weder Fehlermeldungen noch ändert sich der Inhalt der Datei (die MD5-Prüfsumme ändert sich nicht).

Beachten Sie, dass es keine Möglichkeit gibt, die Anwendung einfach rückgängig zu machen, wenn Sie keinen expliziten „Reverse Patch“ erstellen


Ich habe auch getestet, wie die 2,3-MB-Änderung an eine andere Stelle in den abc2 -Daten geschrieben wurde, etwas weiter unten (bei ungefähr 50) MB) sowie zu Beginn. Der generierte „Patch“ war 4,6 MB groß, was darauf hindeutet, dass nur die geänderten Bits im Patch gespeichert wurden.

Kommentare

  • Vielen Dank @Kusalananda, es ‚ ist großartig! PS: rsync --read-batch=abc-diff ${1:-abc} (automatisch generiertes .sh-Skript) gab remote destination is not allowed with --read-batch rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2], aber rsync --read-batch=abc-diff abc hat erfolgreich funktioniert.Was ist der Unterschied zwischen diesen beiden ähnlichen Befehlen?
  • 2/2 Gibt es eine Möglichkeit, abc als Eingabe zu verwenden und den Patch mit --read-batch, aber nicht ändern abc “ an Ort und Stelle „, sondern in eine neue Datei ausgeben abc3? (wenn möglich alle mit rsync, ohne Piping, so dass es problemlos unter Linux und Windows funktioniert, auf denen auch rsync.exe verfügbar ist)
  • @Basj Die Befehle würden verschiedene Dinge tun, wenn $1 einen Wert hätte. ${1:-abc} bedeutet, dass “ den ersten Positionsparameter ($1) verwendet, es sei denn, es ist ‚ ist leer oder undefiniert. Verwenden Sie für den Fall, dass ‚ leer oder undefiniert ist, abc stattdessen „. Ich ‚ gehe davon aus, dass $1 einen Wert hatte, als Sie es versuchten, möglicherweise etwas, das es als a interpretierte Remote-Zieladresse.
  • @Basj Ich ‚ bin nicht ganz sicher, ob dies möglich ist, aber ich ‚ ll Schauen Sie morgen nach dem Schlafengehen nach.
  • Vielen Dank für Ihre Antwort zu ${1:-abc}. Es ist wahrscheinlich fehlgeschlagen, weil ich es unter Windows versucht habe (ich ‚ verwende rsync sowohl unter Linux für meinen entfernten Server als auch unter Windows lokal). Aber ‚ ist perfekt, da rsync --read-batch=abc-diff abc funktioniert 🙂

Antwort

Wie berechnet man einen binären Diff von abc und abc2?

Verwenden von bsdiff / bspatch oder xdelta und anderen.

$ bsdiff older newer patch.bin # patch.bin is created [...] $ bspatch older newer patch.bin # newer is created 

Diese Ermahnungen aus den Manpages sind jedoch zu beachten:

  • bsdiff verwendet Speicher, der 17-mal so groß ist wie oldfile und erfordert eine absolute Mindestgröße des Arbeitssatzes, die das 8-fache der Größe von oldfile beträgt.
  • bspatch verwendet Speicher, der der Größe von oldfile plus der Größe von newfile entspricht, kann jedoch einen sehr kleinen Arbeitssatz ohne dramatischen Leistungsverlust tolerieren.

Kommentare

  • Können Sie möglicherweise ein Beispiel zeigen?
  • Vielen Dank für Ihre Antwort. bsdiff uses memory equal to 17 times the size of oldfile, daher funktioniert ‚ normalerweise nicht für 4-GB-Dateien (zumindest auf meinem 8-GB-RAM-Computer).
  • @Basj Was möglich ist, ist, die 4-GB-Datei in kleinere (z. B. jeweils 128 MB) zu zerlegen und einzelne Deltas zu erstellen. Dies könnte in ein Skript eingeschlossen werden. chopped-bsdiff: Zerhacke die Dateien, mache paarweise bsdiffs, tariere diese in ein Archiv. chopped-bspatch: Lesen Sie paarweise Patches aus dem Archiv, wenden Sie sie auf Teile der Eingabedatei an, verketten Sie die Ausgabe.
  • @Kaz Ich sehe, aber ich ‚ suche mehr Ein sofort einsatzbereites Tool, das unabhängig von der Größe in einer Zeile aufgerufen werden kann (mydiff abc abc2 > patchfile und mypatch abc patchfile > abc3). Wenn ich in 128-MB-Blöcke zerlege, was passiert dann, wenn die ersten 1 GB abc == die letzten (nachfolgenden) 1 GB abc2 ? Wenn wir ‚ abc-first128mb mit abc2-first128mb vergleichen, wird keine Übereinstimmung gefunden möglicherweise nicht effizient?

Antwort

Haben Sie versucht, nur diff, um die Dateien als Text zu behandeln:

diff -ua abc abc2 

Wie hier erläutert .

  • -u gibt NUM-Zeilen (Standard 3) mit einheitlichem Kontext aus
  • -a Behandle alle Dateien als Text.

Dies sollte dir einen Patch bringen. Der Nachteil dabei ist, dass die „Zeilen“ ziemlich lang sein können und das den Patch aufblähen könnte.

Kommentare

  • Ups, ja, Sie tun nicht ‚ möchte eigentlich nicht die n. Ich ‚ bin interessiert zu wissen, ob es funktioniert, da ich ‚ nicht sicher bin, wie lange die “ lines “ wird sein.
  • Vielen Dank für Ihren Kommentar! Ich habe zwei sehr ähnliche 256-MB-Dateien abc und abc2 erstellt. Dann habe ich diff -ua abc abc2 > patch versucht, dann habe ich abc nach abc3 kopiert und versucht, abc2 dank abc3 und patch: patch abc3 < patch, aber es hat nicht funktioniert: Am Ende war abc3 nur 1 KB anstelle von 256 MB. Irgendeine Idee?
  • Hmmm, ich bin mir nicht sicher, was passiert ist. Ich habe es einfach auf meiner Maschine gemacht und es hat besser funktioniert als ich erwartet hatte.Ich habe eine 382M-Datei, die zufällige Ganzzahlen waren, binär in eine Datei geschrieben. Ich habe 3 Bytes darin geändert und das Diff und Patch gemacht und es hat funktioniert. Die resultierenden Dateien waren md5sum gleich.
  • Wenn eine große Datei kein Byte 0x0a hat, dh Zeilenumbruch oder sehr wenige, würde dies vermutlich nicht ‚ funktioniert nicht so gut, es wäre interessant zu testen.
  • Oh, sicher. Sie können mit wc -l eine fundierte Vermutung für eine Binärdatei anstellen, die nach Zeilenumbrüchen sucht und meiner Erfahrung nach sehr schnell ausgeführt wird. Ich würde erwarten, dass eine beliebige Binärdatei ziemlich gut funktioniert. Zum Beispiel fand ich auf meinem Computer einen 252M mp4 mit 1,2 Millionen “ Zeilen “ und einen 59M .deb mit ungefähr 230 KB, also durchschnittliche “ Zeilen “ mit weniger als 220 Byte bzw. 258 Byte. Ich ‚ verstehe nicht, warum diese Dateien so anders sind als andere, aber Sie könnten definitiv Pech haben. In der Praxis vermute ich, dass es ziemlich gut funktionieren würde und wenn nicht, ist es ‚ immer noch ein lustiger Hack.

Antwort

Verwenden Sie xdelta , es wurde genau für diese Art von Verwendung erstellt. Basierend auf VCDIFF (RFC 3284) in den neuesten Versionen.

Kommentare

  • Der Link funktioniert nicht (gibt es eine andere URL?). Sie können auch in einigen Zeilen ein Beispiel hinzufügen, um zu zeigen, wie: 1) die Datei diff patch berechnet und 2) abc2 wiederhergestellt wird , nur abc und patch?
  • Entschuldigung, feste URL
  • Danke @vonbrand . Hätten Sie ein solches Beispiel?

Antwort

Ergänzungen zu anderen Antworten gemäß meinen Tests:

Mit diff

habe ich zwei sehr ähnliche 256-MB-Dateien erstellt abc und abc2. Dann erstellen wir die Diff-Datei:

diff -ua abc abc2 > abc-abc2.diff 

Versuchen wir nun, abc2 dank der wiederherzustellen Original abc -Datei und abc-abc2.diff:

cp abc abc3 patch abc3 < abc-abc2.diff 

oder

cp abc abc3 patch abc3 -i abc-abc2.diff 

oder

patch abc -i abc-abc2.diff -o abc3 

Es funktioniert unter Linux. Ich habe es auch unter Windows versucht (patch.exe und diff.exe sind ebenfalls verfügbar), aber aus einem unbekannten Grund ist dies fehlgeschlagen: Die erstellte abc3 -Datei ist nur 1 KB anstelle von 256 MB (I „). Ich werde diese Antwort später hier aktualisieren.

Mit rsync

Wie in der akzeptierten Antwort beschrieben, funktioniert dies:

rsync --only-write-batch=abc-abc2-diff abc2 abc cp abc abc3 rsync --read-batch=abc-abc2-diff abc3 

Mit rdiff

Wie in beschrieben Antwort , dies ist auch eine Lösung:

rdiff signature abc abc-signature rdiff delta abc-signature abc2 abc-abc2-delta rdiff patch abc abc-abc2-delta abc3 

Getestet auch unter Windows mit rdiff.exe von hier und es funktioniert.

Kommentare

  • Ich ‚ vermute das Der Patch ist unter Windows fehlgeschlagen, da die Eingabedatei im Textmodus “ “ gelesen wurde, der das Dateiende signalisiert, wenn eine STEUERUNG auftritt -Z (Byte 0x18) in der Eingabedatei. Dies ist ein Legacy-Modus aus frühen DOS-Tagen, als das Verzeichnis die Länge von nicht aufzeichnete Die Datei und damit die Dateilänge wurden basierend auf der Anzahl der 512-Byte-Sektoren berechnet. Wenn Sie patch anweisen können, die Datei im Binärmodus zu öffnen, sollte ‚ diesen Fehler nicht haben.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.