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șierabc2
(ar dura din nou câteva ore!) și recreațiabc2
pe distanță server de laabc
șipatch
numai. -
La nivel local, în loc să irosesc 8 GB pentru backup atât
abc
, cât șiabc2
, am putut salva numaiabc
+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
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
șimypatch abc patchfile > abc3
) indiferent de dimensiune. De asemenea, dacă tai în bucăți de 128 MB, ce se întâmplă dacă primul 1 GB dinabc
== ultimul 1 GB (final) de 1 div dinabc2
? Când ‘ vom comparaabc-first128mb
cuabc2-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
șiabc2
. Apoi am încercatdiff -ua abc abc2 > patch
, apoi am copiatabc
înabc3
și am încercat să recuperezabc2
grațieabc3
șipatch
:patch abc3 < patch
, dar nu a funcționat: la sfârșitabc3
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țiabc2
, dat numaiabc
șipatch
? - 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.
rsync --read-batch=abc-diff ${1:-abc}
(scriptul .sh generat automat) a datremote destination is not allowed with --read-batch
rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2]
, darrsync --read-batch=abc-diff abc
a funcționat cu succes.Care este diferența dintre aceste două comenzi similare?abc
ca intrare, aplicați patch-uldiff-abc
cu--read-batch
dar nu modificaabc
” la locul „, ci mai degrabă ieșire într-un fișier nouabc3
? (dacă este posibil, toate cursync
, fără conducte, astfel încât să funcționeze cu ușurință atât pe Linux, cât și pe Windows, care are șirsync.exe
disponibil)$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țiabc
î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ță.${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, deoarecersync --read-batch=abc-diff abc
funcționează 🙂