Forskjellen på to lignende store rå binære filer

La oss si at jeg har en 4 GB fil abc på meg lokal datamaskin. Jeg har lastet den opp til en fjern server via SFTP, det tok noen timer.

Nå har jeg endret filen litt (sannsynligvis maksimalt 50 MB, men ikke påfølgende byte i denne filen) lokalt, og lagret den i abc2. Jeg beholdt også originalfilen abc på min lokale datamaskin.

Hvordan beregne en binær diff på abc og abc2?

Programmer:

  • Jeg kunne bare sende en patch -fil (sannsynligvis maks 100 MB) til den fjerne serveren, i stedet for å laste opp hele abc2 -filen (det vil ta noen timer igjen!), og gjenskape abc2 på den fjerne server fra abc og patch.

  • Lokalt, i stedet for å kaste bort 8 GB for å sikkerhetskopiere både abc og abc2, kunne jeg bare lagre abc + patch, så det tar < bare 4100 MB.

Hvordan gjør jeg dette?

PS: for tekst, jeg vet diff, men her ser jeg etter noe som kan fungere for ethvert rå binært format, det kan være zip-filer eller kjørbare filer eller til og med andre typer filer.

PS2: Hvis det er mulig, vil jeg ikke bruke rsync; Jeg vet at det kan replikere endringer mellom to datamaskiner på en effektiv måte (ikke sende data som ikke er endret på nytt), men her vil jeg virkelig ha en patch -fil, som kan reproduseres senere hvis Jeg har både abc og patch.

Svar

For det andre programmet / problemet vil jeg bruke et dedupliserende sikkerhetskopiprogram som restic eller borgbackup, i stedet for å prøve for å holde styr på «lapper» eller forskjeller manuelt. restic sikkerhetskopiprogrammet lar deg sikkerhetskopiere kataloger fra flere maskiner til samme sikkerhetskopier, og deduplisere sikkerhetskopidataene blant fragmenter av filer fra en enkelt maskin så vel som mellom maskinen. (Jeg har ingen brukererfaring med borgbackup, så jeg kan ikke si noe om det programmet.)

Beregning og lagring av en diff av abc og abc2 filer kan gjøres med rsync.

Dette er et eksempel med abc og abc2 som 153 MB. Filen abc2 er endret ved å overskrive første 2,3 MB av filen med noen andre data:

 $ 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  

Vi lager lapp for å transformere abc til abc2 og kall det 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  

Den genererte filen abc-diff er den faktiske forskjellen («patch-filen»), mens abc-diff.sh eret kort skallskript som rsync oppretter for deg:

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

Dette skriptet endrer abc slik at det blir identisk med abc2, gitt filen abc-diff:

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

Filen abc-diff kan nå overføres til andre steder du har abc. Med kommandoen rsync --read-batch=abc-diff abc vil du bruke oppdateringen på filen abc, og forvandle innholdet til å være det samme som abc2 -filen på systemet der du opprettet diff.

Å bruke plasteret på nytt en gang til virker trygg. Det er ingen feilmeldinger, og innholdet på filen endres ikke (MD5-kontrollsummen endres ikke).

Merk at med mindre du oppretter en eksplisitt «omvendt oppdatering», er det ingen måte å angre applikasjonen enkelt av oppdateringen.


Jeg testet også å skrive 2,3 MB-modifikasjonen til et annet sted i abc2 -dataene, litt lenger inn (omtrent 50 MB), så vel som i begynnelsen. Den genererte «oppdateringen» var 4,6 MB stor, noe som tyder på at bare de modifiserte bitene ble lagret i oppdateringen.

Kommentarer

  • Tusen takk @Kusalananda, det ‘ er flott! PS: rsync --read-batch=abc-diff ${1:-abc} (automatisk generert .sh-skript) ga remote destination is not allowed with --read-batch rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2], men rsync --read-batch=abc-diff abc fungerte vellykket.Hva er forskjellen mellom disse to like kommandoene?
  • 2/2 Er det en måte å ta abc som input, bruke patch diff-abc med --read-batch men ikke modifiser abc » på stedet «, men heller sende ut til en ny fil abc3? (hvis mulig alt med rsync, uten rør, slik at det fungerer enkelt på Linux så vel som Windows som også har rsync.exe tilgjengelig)
  • @Basj Kommandoene ville gjort forskjellige ting hvis $1 hadde en verdi. ${1:-abc} betyr » bruk den første posisjonsparameteren ($1) med mindre den ‘ er tom eller udefinert. Hvis det ‘ er tomt eller udefinert, bruker du abc i stedet for «. Jeg ‘ antar at $1 hadde en verdi når du prøvde det, muligens noe den tolket som ekstern destinasjonsadresse.
  • @Basj I ‘ er ikke helt sikker på at dette er mulig, men jeg ‘ ll ta en titt i morgen etter søvn.
  • Takk for svaret ditt om ${1:-abc}. Det mislyktes sannsynligvis fordi jeg prøvde det på Windows (jeg ‘ m ved hjelp av rsync både på Linux for serveren min og Windows lokalt). Men det ‘ er perfekt siden rsync --read-batch=abc-diff abc fungerer 🙂

Svar

Hvordan beregner du en binær diff på abc og abc2?

Bruker bsdiff / bspatch eller xdelta og andre.

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

Imidlertid skal disse formaningene fra man-sidene bemerkes:

  • bsdiff bruker minne som er lik 17 ganger størrelsen på oldfile , og krever en absolutt minimum arbeidsstørrelse på 8 ganger størrelsen på oldfile .
  • bspatch bruker minne som er lik størrelsen på oldfile pluss størrelsen på newfile , men tåler et veldig lite arbeidssett uten et dramatisk tap av ytelse.

Kommentarer

  • Kan du muligens vise et eksempel?
  • Takk for svaret. bsdiff uses memory equal to 17 times the size of oldfile så dette vant ‘ t fungerer vanligvis ikke for 4 GB filer (i det minste på min 8 GB RAM-maskin).
  • @Basj Det som er mulig er å hugge opp 4 GB-filen til mindre (si 128 MB hver), og gjøre individuelle deltaer. Dette kan pakkes inn i et skript. hakket-bsdiff: hakk filene, gjør parvise bsdiffer, tar dem opp i et arkiv. chopped-bspatch: les parvise lapper fra arkivet, bruk på biter av inndatafilen, sammenkoble utdata.
  • @Kaz ser jeg, men jeg ‘ m mer på jakt etter et brukervennlig verktøy som kan kalles på 1 linje (mydiff abc abc2 > patchfile og mypatch abc patchfile > abc3) uansett størrelse. Også, hvis jeg hakker i 128 MB biter, hva skjer hvis den første 1 GB abc == den siste (etterfølgende) 1 GB abc2 ? Når vi ‘ sammenligner abc-first128mb med abc2-first128mb, vil ingen treff bli funnet, så det kanskje ikke effektiv?

Svar

Har du prøvd å bare tvinge diff for å behandle filene som tekst:

diff -ua abc abc2 

Som forklart her .

  • -u output NUM (standard 3) linjer i enhetlig kontekst
  • -a behandle alle filer som tekst

Dette skal gi deg en oppdatering. Ulempen med dette er at «linjene» kan være ganske lange, og det kan oppblåse plasteret.

Kommentarer

  • Ups, ja du don ‘ t vil faktisk ha n. Jeg ‘ er interessert i å vite om det fungerer som jeg ‘ er usikker på hvor lenge » linjer » vil være.
  • Takk for kommentaren din! Jeg opprettet to veldig like 256 MB filer abc og abc2. Så prøvde jeg diff -ua abc abc2 > patch, så kopierte jeg abc til abc3 og jeg prøvde å gjenopprette abc2 takket være abc3 og patch: patch abc3 < patch, men det fungerte ikke: på slutten var abc3 bare 1KB i stedet for 256 MB. Noen ide?
  • Hmmm, ikke sikker på hva som skjedde. Jeg gjorde det bare på maskinen min, og det fungerte bedre enn jeg hadde forventet.Jeg tok en 382M fil som var tilfeldige heltall skrevet ut i binær fil til en fil. Jeg byttet 3 byte i den og gjorde diff og patch, og det fungerte. De resulterende filene var md5sum like.
  • Hvis en stor fil ikke har byte 0x0a, dvs. ny linje, eller veldig få, tror jeg at den ikke ville ‘ fungerer ikke så bra, det ville være interessant å teste.
  • Å helt sikkert. Du kan lage en utdannet gjetning på en binær med wc -l som vil se etter linjeskift og etter min erfaring kjører veldig raskt. Jeg forventer at det vil fungere ganske bra på en vilkårlig binær. For eksempel på maskinen min fant jeg en 252M mp4 som hadde 1,2 millioner » linjer «, og en 59M .deb som hadde omtrent 230k, så gjennomsnitt » linjer » på henholdsvis mindre enn 220 byte og 258 byte. Jeg ser ikke ‘ hvorfor disse filene ville være så forskjellige enn andre, men du kan definitivt bli uheldig. I praksis mistenker jeg at det ville fungere ganske bra, og hvis ikke, er det ‘ fortsatt et morsomt hack.

Svar

Bruk xdelta , den ble opprettet nøyaktig for denne typen bruk. Basert på VCDIFF (RFC 3284) i de nyeste versjonene.

Kommentarer

  • Koblingen fungerer ikke (er det en annen URL?). Kan du også legge til et eksempel på noen få linjer for å vise hvordan du: 1) beregner diff patch -filen, og 2) gjenoppretter abc2 , bare gitt abc og patch?
  • Beklager, fast URL
  • Takk @vonbrand . Vil du ha et slikt eksempel?

Svar

Utfyller andre svar i henhold til testene mine:

Med diff

opprettet jeg to veldig like 256 MB filer abc og abc2. La oss deretter opprette diff-filen:

diff -ua abc abc2 > abc-abc2.diff 

La oss nå prøve å gjenopprette abc2 takket være original abc fil og abc-abc2.diff:

cp abc abc3 patch abc3 < abc-abc2.diff 

eller

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

eller

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

Det fungerer på Linux. Jeg prøvde også på Windows (patch.exe og diff.exe er også tilgjengelig), men av en ukjent grunn mislyktes det: den produserte abc3 filen er bare 1KB i stedet for 256MB (I » Oppdater dette svaret senere her).

Med rsync

Som beskrevet i det aksepterte svaret, fungerer dette:

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

Med rdiff

Som beskrevet i dette svar , dette er også en løsning:

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

Testet også på Windows med rdiff.exe fra her og det fungerer.

Kommentarer

  • Jeg ‘ jeg gjetter at oppdateringen mislyktes på Windows fordi den leste inndatafilen i » tekst » -modus som signaliserer slutten av filen når den møter en KONTROLL -Z (byte 0x18) i inndatafilen. Dette er en eldre modus fra tidlige DOS-dager da katalogen ikke registrerte lengden på filen og så ble fillengden beregnet basert på antall 512 byte sektorer. Hvis du kan fortelle patch om å åpne filen i binær modus, bør den ikke ‘ ikke ha denne feilen.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *