Diff de două fișiere binare mari mari similare

Să spunem că am un fișier de 4 GB abc computer local. L-am încărcat pe un server îndepărtat prin SFTP, a durat câteva ore.

Acum am modificat ușor fișierul (probabil 50 MB maximum, dar nu octeți consecutivi în acest fișier) la nivel local, și l-am salvat în abc2. De asemenea, am păstrat fișierul original abc pe computerul meu local.

Cum se calculează o diferență binară de abc și abc2?

Aplicații:

  • Aș putea trimite doar un fișier patch (probabil maximum 100 MB) către serverul îndepărtat, în loc să reîncărcați întregul fișier abc2 (ar dura din nou câteva ore!) și recreați abc2 pe distanță server de la abc și patch numai.

  • La nivel local, în loc să irosesc 8 GB pentru backup atât abc, cât și abc2, am putut salva numai abc + patch, deci ar dura < numai 4100 MB.

Cum se face acest lucru?

PS: pentru text, știu diff, dar aici caut ceva care ar putea funcționa pentru orice format binar brut, ar putea fi fișiere zip sau executabile sau chiar alte tipuri de fișiere.

PS2: Dacă este posibil, nu vreau să folosesc rsync; Știu că poate replica modificările între 2 computere într-un mod eficient (fără a retrimite datele care nu s-au modificat), dar aici chiar vreau să am un fișier patch, care poate fi reprodus ulterior dacă Am atât abc, cât și patch.

Răspuns

Pentru a doua aplicație / problemă, aș folosi un program de copiere de rezervă deduplicant precum restic sau borgbackup, mai degrabă decât să încerc pentru a urmări manual „patch-uri” sau diff-uri. Programul de rezervă restic vă permite să faceți copii de rezervă ale directoarelor de la mai multe mașini în același depozit de backup, deduplicând datele de rezervă atât între fragmente de fișiere de la o mașină individuală, cât și între mașină. (Nu am experiență de utilizator cu borgbackup, așa că nu pot spune nimic despre acel program.)

Calcularea și stocarea unei diferențe a și abc2 pot fi făcute cu rsync.

Acesta este un exemplu cu abc și abc2 fiind de 153 MB. Fișierul abc2 a fost modificat prin suprascrierea primul 2,3 MB al fișierului cu alte date:

 $ 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  

Creăm patch pentru transformarea abc în abc2 și numiți-l 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  

Fișierul generat abc-diff este diferența reală („fișierul patch”), în timp ce abc-diff.sh esteun scurt script shell pe care rsync îl creează:

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

Acest script modifică abc astfel încât să devină identic cu abc2, având în vedere fișierul abc-diff:

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

Fișierul abc-diff ar putea fi acum transferat oriunde altundeva aveți abc. Cu comanda rsync --read-batch=abc-diff abc, veți aplica patch-ul la fișierul abc, transformând conținutul acestuia în același cu abc2 de pe sistemul în care ați creat dif.

Re-aplicarea patch-ului a doua oară pare sigură. Nu există mesaje de eroare și nici conținutul fișierului nu se modifică (suma de verificare MD5 nu se modifică).

Rețineți că, dacă nu creați un „patch invers” explicit, nu există nicio modalitate de a anula cu ușurință aplicația. a patch-ului.


De asemenea, am testat scrierea modificării de 2,3 MB într-un alt loc în datele abc2, puțin mai departe în (la aproximativ 50 MB), precum și la început. „Patch-ul” generat avea o dimensiune de 4,6 MB, sugerând că numai biții modificați au fost stocați în patch-uri.

Comentarii

  • Mulțumesc mult @Kusalananda, ‘ este minunat! PS: rsync --read-batch=abc-diff ${1:-abc} (scriptul .sh generat automat) a dat remote destination is not allowed with --read-batch rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2], dar rsync --read-batch=abc-diff abc a funcționat cu succes.Care este diferența dintre aceste două comenzi similare?
  • 2/2 Există o modalitate de a lua abc ca intrare, aplicați patch-ul diff-abc cu --read-batch dar nu modifica abc ” la locul „, ci mai degrabă ieșire într-un fișier nou abc3? (dacă este posibil, toate cu rsync, fără conducte, astfel încât să funcționeze cu ușurință atât pe Linux, cât și pe Windows, care are și rsync.exe disponibil)
  • @Basj Comenzile ar face lucruri diferite dacă $1 ar avea o valoare. ${1:-abc} înseamnă ” utilizați primul parametru pozițional ($1), cu excepția cazului în care este gol sau nedefinit. În cazul în care ‘ este gol sau nedefinit, utilizați abc în loc de „. ‘ presupunând că $1 a avut o valoare când ați încercat-o, posibil ceva pe care l-a interpretat ca adresa de destinație la distanță.
  • @Basj Nu ‘ nu sunt complet sigur că acest lucru este posibil, dar ‘ ll aruncă o privire mâine după somn.
  • Vă mulțumim pentru răspunsul dvs. despre ${1:-abc}. Probabil că a eșuat din cauză că l-am încercat pe Windows (eu ‘ m folosind rsync atât pe Linux pentru serverul meu îndepărtat, cât și Windows local). Dar ‘ este perfect, deoarece rsync --read-batch=abc-diff abc funcționează 🙂

Răspuns

Cum se calculează o diferență binară dintre abc și abc2?

Utilizarea bsdiff / bspatch sau xdelta și altele.

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

Cu toate acestea, aceste avertismente din paginile manual trebuie menționate:

  • bsdiff folosește memorie egală cu de 17 ori dimensiunea oldfile și necesită o dimensiune minimă absolută a setului de lucru de 8 ori dimensiunea oldfile .
  • bspatch folosește memorie egală cu dimensiunea oldfile plus dimensiunea newfile , dar poate tolera un set de lucru foarte mic fără o pierdere dramatică de performanță.

Comentarii

  • Ați putea afișa un exemplu?
  • Vă mulțumim pentru răspuns. bsdiff uses memory equal to 17 times the size of oldfile, deci acest lucru nu va funcționa ‘ de obicei, pentru fișiere de 4 GB (cel puțin pe aparatul meu RAM de 8 GB).
  • @Basj Ceea ce este posibil este să tăiați fișierul de 4 GB în altele mai mici (să zicem 128 MB fiecare) și să faceți delta individuale. Acest lucru ar putea fi înfășurat într-un script. chopped-bsdiff: tăiați fișierele, faceți bsdiffs în perechi, tastați-le într-o arhivă. chopped-bspatch: citiți patch-uri perechi din arhivă, aplicați bucăți de fișier de intrare, catenați ieșirea.
  • @Kaz văd, dar eu ‘ m mai căutam un instrument gata de utilizare care poate fi apelat pe o linie (mydiff abc abc2 > patchfile și mypatch abc patchfile > abc3) indiferent de dimensiune. De asemenea, dacă tai în bucăți de 128 MB, ce se întâmplă dacă primul 1 GB din abc == ultimul 1 GB (final) de 1 div din abc2 ? Când ‘ vom compara abc-first128mb cu abc2-first128mb, nu se va găsi nicio potrivire, așa că s-ar putea să nu fie eficient?

Răspuns

Ați încercat doar să forțați diff pentru a trata fișierele ca text:

diff -ua abc abc2 

Așa cum s-a explicat aici .

  • -u ieșire NUM (implicit 3) linii de context unificat
  • -a tratați toate fișierele ca text

Acest lucru ar trebui să vă ofere un patch. Dezavantajul este că „liniile” ar putea fi destul de lungi și ar putea umfla patch-ul.

Comentarii

  • Hopa, da, nu ‘ nu doresc de fapt n. ‘ mă interesează să știu dacă funcționează așa cum ‘ nu sunt sigur cât timp ” lines ” vor fi.
  • Vă mulțumim pentru comentariu! Am creat două fișiere foarte similare de 256 MB abc și abc2. Apoi am încercat diff -ua abc abc2 > patch, apoi am copiat abc în abc3 și am încercat să recuperez abc2 grație abc3 și patch: patch abc3 < patch, dar nu a funcționat: la sfârșit abc3 avea doar 1 KB în loc de 256 MB. Ai vreo idee?
  • Hmmm, nu sunt sigur ce s-a întâmplat. Tocmai am făcut-o pe mașina mea și a funcționat mai bine decât mă așteptasem.Am luat un fișier 382M, care a fost numere întregi aleatoare scrise în binar într-un fișier. Am schimbat 3 octeți în el și am făcut diferența și patch-ul și a funcționat. Fișierele rezultate au fost md5sum egale.
  • Dacă un fișier mare nu are octet 0x0a, adică linie nouă, sau foarte puține, bănuiesc că nu ar fi ‘ nu funcționează atât de bine, ar fi interesant de testat.
  • Oh, sigur. Puteți face o presupunere educată pe un binar cu wc -l care va căuta întreruperi de linie și, în experiența mea, rulează foarte repede. M-aș aștepta la un binar arbitrar că ar funcționa destul de bine. De exemplu, pe mașina mea am găsit un mp4 de 252M care avea 1,2 milioane ” linii ” și un 59M .deb care avea aproximativ 230k, deci ” linii medii ” mai mici de 220 octeți și respectiv 258 octeți. Nu ‘ nu văd de ce aceste fișiere ar fi atât de diferite decât altele, dar cu siguranță ai putea avea ghinion. În practică bănuiesc că ar funcționa destul de bine și dacă nu ‘ este încă un hack distractiv.

Răspuns

Utilizați xdelta , a fost creat exact pentru acest tip de utilizări. Bazat pe VCDIFF (RFC 3284) în ultimele versiuni.

Comentarii

  • Linkul nu funcționează (mai există o altă adresă URL?). De asemenea, ați putea adăuga un exemplu în câteva rânduri pentru a arăta cum să: 1) calculați fișierul dif patch și 2) să restaurați abc2 , dat numai abc și patch?
  • Ne pare rău, adresa URL fixă
  • Mulțumesc @vonbrand . Ați avea un astfel de exemplu?

Răspuns

Complimente la alte răspunsuri conform testelor mele:

Cu diff

am creat două fișiere foarte similare de 256 MB abc și abc2. Apoi, să creăm fișierul diff:

diff -ua abc abc2 > abc-abc2.diff 

Acum, să încercăm să recuperăm abc2 datorită fișier abc original și abc-abc2.diff:

cp abc abc3 patch abc3 < abc-abc2.diff 

sau

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

sau

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

Funcționează pe Linux. Am încercat și pe Windows (patch.exe și diff.exe sunt disponibile și), dar dintr-un motiv necunoscut a eșuat: fișierul abc3 produs are doar 1 KB în loc de 256 MB (I „) Voi actualiza acest răspuns mai târziu aici).

Cu rsync

După cum este detaliat în răspunsul acceptat, acest lucru funcționează:

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

Cu rdiff

Așa cum este detaliat în răspuns , aceasta este și o soluție:

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

Testat și pe Windows cu rdiff.exe din aici și funcționează.

Comentarii

  • ‘ presupun că patch-ul nu a reușit pe Windows deoarece citea fișierul de intrare în modul ” text ” care semnalizează sfârșitul fișierului atunci când întâlnește un CONTROL -Z (octet 0x18) în fișierul de intrare. Acesta este un mod moștenit din primele zile DOS când directorul nu a înregistrat lungimea fișierul și astfel lungimea fișierului a fost calculat pe baza numărului de sectoare de 512 octeți. Dacă puteți spune patch să deschidă fișierul în modul binar, nu ar trebui să ‘ să aibă această eroare.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *