Differenza di due file binari grezzi simili

Supponiamo che io abbia un file da 4 GB abc sul mio computer locale. Lho caricato su un server distante tramite SFTP, ci sono volute alcune ore.

Ora ho leggermente modificato il file (probabilmente 50 MB al massimo, ma non byte consecutivi in questo file) localmente, e lho salvato in abc2. Ho anche mantenuto il file originale abc sul mio computer locale.

Come calcolare una differenza binaria di abc e abc2?

Applicazioni:

  • ho potuto inviare solo un file patch (probabilmente max 100 MB) a il server distante, invece di ricaricare lintero file abc2 (ci vorrebbero ancora alcune ore!) e ricreare abc2 sul server remoto server solo da abc e patch.

  • A livello locale, invece di sprecare 8 GB per il backup di abc e abc2, ho potuto salvare solo abc + patch, quindi sono necessari < solo 4100 MB.

Come si fa?

PS: per il testo, so diff, ma qui sto cercando qualcosa che potrebbe funzionare per qualsiasi formato binario grezzo, potrebbe essere file zip o eseguibili o anche altri tipi di file.

PS2: Se possibile, non voglio utilizzare rsync; So che può replicare le modifiche tra 2 computer in modo efficiente (non rispedire i dati che non sono cambiati), ma qui voglio davvero avere un file patch, che è riproducibile in seguito se Ho sia abc e patch.

Risposta

Per la seconda applicazione / problema, utilizzerei un programma di backup di deduplicazione come restic o borgbackup, invece di provare per tenere traccia manualmente di “patch” o diff. Il programma di backup restic consente di eseguire il backup di directory da più macchine allo stesso repository di backup, deduplicando i dati di backup sia tra frammenti di file da una singola macchina che tra macchine. (Non ho esperienza utente con borgbackup, quindi non posso “dire nulla su quel programma.)

Calcolo e memorizzazione di una differenza di abc e abc2 possono essere eseguiti con rsync.

Questo è un esempio con abc e abc2 pari a 153 MB. Il file abc2 è stato modificato sovrascrivendo il primi 2,3 MB del file con alcuni altri dati:

 $ 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  

Creiamo patch per trasformare abc in abc2 e chiamarlo 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  

Il file generato abc-diff è il diff effettivo (il tuo “file patch”), mentre abc-diff.sh èun breve script della shell che rsync crea per te:

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

Questo script modifica abc in modo che diventi identico a abc2, dato il file abc-diff:

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

Il file ovunque tu abbia abc. Con il comando rsync --read-batch=abc-diff abc, applicheresti la patch al file abc, trasformandone il contenuto in modo che corrisponda a abc2 sul sistema in cui hai creato il diff.

Riapplicare la patch una seconda volta sembra sicuro. Non ci sono messaggi di errore né il contenuto del file cambia (il checksum MD5 non cambia).

Nota che a meno che tu non crei una “patch inversa” esplicita, non cè modo di annullare facilmente lapplicazione della patch.


Ho anche provato a scrivere la modifica da 2,3 MB in qualche altro posto nei dati abc2, un po più avanti (a circa 50 MB), così come allinizio. La “patch” generata era grande 4,6 MB, suggerendo che solo i bit modificati erano stati memorizzati nella patch.

Commenti

  • Grazie mille @Kusalananda, ‘ è fantastico! PS: rsync --read-batch=abc-diff ${1:-abc} (script .sh generato automaticamente) ha fornito remote destination is not allowed with --read-batch rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2], ma rsync --read-batch=abc-diff abc ha funzionato correttamente.Qual è la differenza tra questi due comandi simili?
  • 2/2 Cè un modo per utilizzare abc come input, applicare la patch diff-abc con --read-batch ma non modificare abc ” sul posto “, ma piuttosto output in un nuovo file abc3? (se possibile tutto con rsync, senza piping, in modo che funzioni facilmente su Linux e Windows che ha anche rsync.exe disponibile)
  • @Basj I comandi farebbero cose diverse se $1 avesse un valore. ${1:-abc} significa che ” utilizza il primo parametro posizionale ($1) a meno che non ‘ è vuoto o non definito. Nel caso in cui ‘ sia vuoto o non definito, utilizza abc invece “. ‘ presumo che $1 avesse un valore quando lhai provato, forse qualcosa che ha interpretato come un indirizzo di destinazione remota.
  • @Basj I ‘ non sono del tutto sicuro che sia possibile, ma ‘ ll dai unocchiata domani dopo aver dormito.
  • Grazie per la tua risposta su ${1:-abc}. Probabilmente non è riuscito perché lho provato su Windows (io ‘ sto usando rsync sia su Linux per il mio server distante che su Windows localmente). Ma ‘ è perfetto poiché rsync --read-batch=abc-diff abc funziona 🙂

Risposta

Come calcolare una differenza binaria di abc e abc2?

Utilizzo di bsdiff / bspatch o xdelta e altri.

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

Tuttavia, questi ammonimenti dalle pagine man devono essere notati:

  • bsdiff usa una memoria pari a 17 volte la dimensione di oldfile e richiede una dimensione del working set minima assoluta di 8 volte la dimensione del oldfile .
  • bspatch utilizza una memoria pari alla dimensione di oldfile più la dimensione di newfile , ma può tollerare un working set molto piccolo senza una drammatica perdita di prestazioni.

Commenti

  • Potresti mostrare un esempio?
  • Grazie per la tua risposta. bsdiff uses memory equal to 17 times the size of oldfile quindi ‘ di solito non funziona con file da 4 GB (almeno sulla mia macchina con RAM da 8 GB).
  • @Basj Ciò che è possibile è tagliare il file da 4 GB in file più piccoli (diciamo 128 MB ciascuno) e fare delta individuali. Questo potrebbe essere inserito in uno script. chopped-bsdiff: tagliare i file, eseguire bsdiff a coppie, archiviarli in un archivio. chopped-bspatch: legge le patch a coppie dallarchivio, si applica a blocchi di file di input, catenate loutput.
  • @Kaz vedo, ma ‘ sto più cercando uno strumento pronto per luso che può essere richiamato in 1 riga (mydiff abc abc2 > patchfile e mypatch abc patchfile > abc3) indipendentemente dalle dimensioni. Inoltre, se divido in blocchi da 128 MB, cosa succede se il primo 1 GB di abc == lultimo (finale) 1 GB di abc2 ? Quando ‘ confronteremo abc-first128mb con abc2-first128mb, non verrà trovata alcuna corrispondenza, quindi potrebbe non essere efficiente?

Risposta

Hai provato a forzare diff per trattare i file come testo:

diff -ua abc abc2 

Come spiegato qui .

  • -u restituisce NUM (predefinito 3) righe di contesto unificato
  • -a tratta tutti i file come testo

Questo dovrebbe farti ottenere una patch. Lo svantaggio di questo è che le “righe” potrebbero essere piuttosto lunghe e questo potrebbe gonfiare la patch.

Commenti

  • Oops, sì, non ‘ in realtà voglio n. ‘ mi interessa sapere se funziona perché ‘ non so per quanto tempo ” lines ” lo saranno.
  • Grazie per il tuo commento! Ho creato due file da 256 MB molto simili abc e abc2. Poi ho provato diff -ua abc abc2 > patch, poi ho copiato abc in abc3 e ho provato a recuperare abc2 grazie a abc3 e patch: patch abc3 < patch, ma non ha funzionato: alla fine abc3 era solo di 1 KB invece di 256 MB. Qualche idea?
  • Hmmm, non sono sicuro di cosa sia successo. Lho appena fatto sulla mia macchina e ha funzionato meglio di quanto mi aspettassi.Ho preso un file 382M che era numeri interi casuali scritti in binario in un file. Ho cambiato 3 byte in esso e ho fatto il diff e la patch e ha funzionato. I file risultanti erano md5sum uguali.
  • Se un file di grandi dimensioni non ha byte 0x0a, ovvero newline o pochissimi, sospetto che non lo farebbe ‘ t funziona così bene, sarebbe interessante testarlo.
  • Oh di sicuro. Puoi fare unipotesi plausibile su un binario con wc -l che cercherà le interruzioni di riga e nella mia esperienza viene eseguito molto rapidamente. Mi aspetterei che su un binario arbitrario funzionasse abbastanza bene. Ad esempio, sulla mia macchina ho trovato un 252 M mp4 con 1,2 milioni di ” linee ” e un 59 M .deb che aveva circa 230 kB, quindi ” righe ” inferiore a 220 byte e 258 byte rispettivamente. Non ‘ non vedo perché questi file sarebbero così diversi dagli altri, ma potresti sicuramente essere sfortunato. In pratica sospetto che funzionerebbe abbastanza bene e in caso contrario ‘ è ancora un trucco divertente.

Risposta

Usa xdelta , è stato creato proprio per questo tipo di utilizzi. Basato su VCDIFF (RFC 3284) nelle ultime versioni.

Commenti

  • Il collegamento non funziona (cè un altro URL?). Potresti anche aggiungere un esempio in poche righe per mostrare come: 1) calcolare il file diff patch e 2) ripristinare abc2 , dati solo abc e patch?
  • Scusa, URL corretto
  • Grazie @vonbrand . Avresti un esempio del genere?

Risposta

Si integra con altre risposte in base ai miei test:

Con diff

ho creato due file da 256 MB molto simili abc e abc2. Quindi creiamo il file diff:

diff -ua abc abc2 > abc-abc2.diff 

Ora proviamo a recuperare abc2 grazie al file abc originale e abc-abc2.diff:

cp abc abc3 patch abc3 < abc-abc2.diff 

o

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

o

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

Funziona su Linux. Ho provato anche su Windows (sono disponibili anche patch.exe e diff.exe), ma per un motivo sconosciuto non è riuscito: il file abc3 prodotto è di solo 1 KB invece di 256 MB (I ” aggiornerò questa risposta più avanti qui).

Con rsync

Come spiegato in dettaglio nella risposta accettata, funziona:

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

Con rdiff

Come descritto in questo answer , anche questa è una soluzione:

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

Testato anche su Windows con rdiff.exe da qui e funziona.

Commenti

  • ‘ immagino che patch non riuscita su Windows perché stava leggendo il file di input in modalità ” text ” che segnala la fine del file quando incontra un CONTROL -Z (byte 0x18) nel file di input. Questa è una modalità legacy dai primi giorni del DOS, quando la directory non registrava la lunghezza di il file e quindi la lunghezza del file è stata calcolata in base al numero di settori da 512 byte. Se puoi dire a patch di aprire il file in modalità binaria, non dovrebbe ‘ avere questo errore.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *