Skillnaden mellan två liknande stora råa binära filer

Låt oss säga att jag har en 4 GB-fil abc på min lokal dator. Jag har laddat upp den till en avlägsen server via SFTP, det tog några timmar.

Nu har jag modifierat filen lite (troligen 50 MB maximalt, men inte på varandra följande byte i den här filen) lokalt, och sparade den i abc2. Jag behöll också originalfilen abc på min lokala dator.

Hur man beräknar en binär diff på abc och abc2?

Applikationer:

  • Jag kunde bara skicka en patch -fil (troligen max 100 MB) till den avlägsna servern istället för att ladda upp hela abc2 -filen (det skulle ta några timmar igen!) och återskapa abc2 på den avlägsna endast från abc och patch.

  • Lokalt, istället för att slösa bort 8 GB för att säkerhetskopiera både abc och abc2, kunde jag bara spara abc + patch, så det tar < endast 4100 MB.

Hur gör man det?

PS: för text vet jag diff, men här letar jag efter något som kan fungera för alla råa binära format, det kan vara zip-filer eller körbara filer eller till och med andra typer av filer.

PS2: Om möjligt vill jag inte använda rsync; Jag vet att det kan replikera ändringar mellan två datorer på ett effektivt sätt (inte skicka data som inte har ändrats), men här vill jag verkligen ha en patch -fil, som kan reproduceras senare om Jag har både abc och patch.

Svar

För den andra applikationen / frågan skulle jag använda ett deduplicering av säkerhetskopieringsprogram som restic eller borgbackup, snarare än att försöka för att manuellt hålla reda på ”lappar” eller skillnader. restic säkerhetskopieringsprogrammet gör att du kan säkerhetskopiera kataloger från flera datorer till samma säkerhetskopia och deduplicera säkerhetskopieringsdata både bland fragment av filer från en enskild maskin och mellan en maskin. (Jag har ingen användarupplevelse med borgbackup, så jag kan inte säga något om det programmet.)

Beräkning och lagring av skillnaden mellan abc och abc2 filer kan göras med rsync.

Detta är ett exempel med abc och abc2 153 MB. Filen abc2 har ändrats genom att skriva över första 2,3 MB av filen med några andra 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 skapar lapp för att omvandla abc till abc2 och kalla 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 genererade filen abc-diff är den faktiska diff (din ”patchfil”), medan abc-diff.sh ärett kort skalskript som rsync skapar åt dig:

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

Detta skript ändrar abc så att det blir identiskt med abc2, med tanke på 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 nu överföras till vart du än har abc. Med kommandot rsync --read-batch=abc-diff abc applicerar du korrigeringsfilen på filen abc och förvandlar dess innehåll till samma som abc2 -fil på systemet där du skapade diff.

Återanvändning av plåstret en andra gång verkar säkert. Det finns inga felmeddelanden och inte heller ändras filens innehåll (kontrollsumman för MD5 ändras inte).

Observera att om du inte skapar en uttrycklig ”omvänd patch” finns det inget sätt att ångra applikationen av korrigeringsfilen.


Jag testade också att skriva 2,3 MB-modifieringen till någon annan plats i abc2 -data, lite längre in (vid cirka 50 MB) såväl som i början. Den genererade ”patch” var 4,6 MB stor, vilket tyder på att endast de modifierade bitarna lagrades i patch.

Kommentarer

  • Tack så mycket @Kusalananda, det ’ är fantastiskt! PS: rsync --read-batch=abc-diff ${1:-abc} (automatiskt genererat .sh-skript) gav 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 fungerade framgångsrikt.Vad är skillnaden mellan dessa två liknande kommandon?
  • 2/2 Finns det ett sätt att ta abc som inmatning, applicera plåstret diff-abc med --read-batch men ändrar inte abc ” på plats ”, utan snarare mata ut till en ny fil abc3? (om möjligt allt med rsync, utan piping, så att det fungerar enkelt på Linux såväl som Windows som också har rsync.exe tillgängligt)
  • @Basj Kommandona skulle göra olika saker om $1 hade ett värde. ${1:-abc} betyder ” använd den första positionsparametern ($1) såvida det inte är ’ är tomt eller odefinierat. Om det ’ är tomt eller odefinierat, använd abc istället ”. Jag ’ antar att $1 hade ett värde när du försökte det, möjligen något som det tolkade som en fjärrmålsadress.
  • @Basj I ’ Jag är inte helt säker på att detta är möjligt, men jag ’ ll ta en titt imorgon efter sömn.
  • Tack för ditt svar om ${1:-abc}. Det misslyckades förmodligen beror på att jag försökte det på Windows (jag ’ m med rsync både på Linux för min avlägsna server och Windows lokalt). Men det är ’ perfekt eftersom rsync --read-batch=abc-diff abc fungerar 🙂

Svar

Hur man beräknar en binär diff av abc och abc2?

Med bsdiff / bspatch eller xdelta och andra.

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

Dessa förmaningar från man-sidorna bör dock noteras:

  • bsdiff använder minne som är lika med 17 gånger storleken på oldfile , och kräver en absolut minsta arbetsuppsättningsstorlek på 8 gånger storleken på oldfile .
  • bspatch använder minne som är lika med storleken på oldfile plus storleken på newfile , men tål en mycket liten arbetsuppsättning utan en dramatisk förlust av prestanda.

Kommentarer

  • Kan du eventuellt visa ett exempel?
  • Tack för ditt svar. bsdiff uses memory equal to 17 times the size of oldfile så det här vinner ’ fungerar vanligtvis inte för 4 GB-filer (åtminstone på min 8 GB RAM-maskin).
  • @Basj Vad som är möjligt är att hugga upp 4 GB-filen i mindre (säg 128 MB vardera) och göra enskilda deltor. Detta kan läggas in i ett manus. chopped-bsdiff: hugga filerna, gör parvis bsdiffs, tjära upp dem i ett arkiv. chopped-bspatch: läs parvisa fläckar från arkivet, tillämpas på bitar av inmatningsfilen, catenate output.
  • @Kaz ser jag, men jag ’ m mer ute ett färdigt verktyg som kan anropas på en rad (mydiff abc abc2 > patchfile och mypatch abc patchfile > abc3) oavsett storlek. Om jag hackar i 128 MB bitar, vad händer om den första 1 GB abc == den sista (efterföljande) 1 GB abc2 ? När vi ’ jämför abc-first128mb med abc2-first128mb, kommer ingen matchning att hittas, så det kanske inte är effektiv?

Svar

Har du försökt att bara tvinga diff för att behandla filerna som text:

diff -ua abc abc2 

Som förklaras här .

  • -u utgång NUM (standard 3) rader i enhetligt sammanhang
  • -a behandla alla filer som text

Detta skulle ge dig en korrigering. Nackdelen med detta är att ”raderna” kan vara ganska långa och det kan svälla plåstret. id = ”c166a34583”>

t vill faktiskt han. Jag ’ är intresserad av att veta om det fungerar som jag ’ jag är inte säker på hur länge ” rader ” kommer att vara.

  • Tack för din kommentar! Jag skapade två mycket lika 256 MB-filer abc och abc2. Sedan försökte jag diff -ua abc abc2 > patch, sedan kopierade jag abc till abc3 och jag försökte återhämta mig abc2 tack vare abc3 och patch: patch abc3 < patch, men det fungerade inte: i slutet var abc3 bara 1KB istället för 256 MB. Någon idé?
  • Hmmm, inte säker på vad som hände. Jag gjorde det bara på min maskin och det fungerade bättre än jag hade förväntat mig.Jag tog en 382M-fil som var slumpmässiga heltal skrivna ut i binär till en fil. Jag bytte 3 byte i den och gjorde diff och patch och det fungerade. De resulterande filerna var md5sum lika.
  • Om en stor fil inte har någon byte 0x0a, dvs newline, eller mycket få, misstänker jag att den inte skulle ’ fungerar inte så bra, det skulle vara intressant att testa.
  • Åh säker. Du kan göra en utbildad gissning på en binär med wc -l som kommer att leta efter radbrytningar och enligt min erfarenhet går mycket snabbt. Jag förväntar mig att det på en godtycklig binär fungerar bra. Till exempel på min maskin hittade jag en 252M mp4 som hade 1,2 miljoner ” rader ” och en 59M .deb som hade cirka 230k, så ” rader ” på mindre än 220 byte respektive 258 byte. Jag förstår inte ’ varför dessa filer skulle vara så annorlunda än andra men du kan definitivt bli otur. I praktiken misstänker jag att det skulle fungera ganska bra och om inte så är det ’ fortfarande ett roligt hack.
  • Svar

    Använd xdelta , det skapades exakt för denna typ av användning. Baserat på VCDIFF (RFC 3284) i de senaste versionerna.

    Kommentarer

    • Länken fungerar inte (finns det en annan URL?). Kan du också lägga till ett exempel på några rader för att visa hur du: 1) beräknar diff patch -filen och 2) återställer abc2 , ges endast abc och patch?
    • Tyvärr, fixad webbadress
    • Tack @vonbrand . Skulle du ha ett sådant exempel?

    Svar

    Kompletterar andra svar enligt mina tester:

    Med diff

    skapade jag två mycket lika 256 MB-filer abc och abc2. Låt oss sedan skapa diff-filen:

    diff -ua abc abc2 > abc-abc2.diff 

    Låt oss försöka återställa abc2 tack vare original abc fil och 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 fungerar på Linux. Jag försökte också på Windows (patch.exe och diff.exe finns också), men av okänd anledning misslyckades det: den producerade abc3 -filen är bara 1KB istället för 256MB (I ” Uppdaterar det här svaret senare här).

    Med rsync

    Som detaljerat i det accepterade svaret fungerar detta:

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

    Med rdiff

    Så detaljerat i detta svara , det här är också en lösning:

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

    Testat också på Windows med rdiff.exe från här och det fungerar.

    Kommentarer

    • Jag ’ jag gissar att korrigeringen misslyckades i Windows eftersom den läste inmatningsfilen i ” text ” -läge som signalerar slutet på filen när den möter en KONTROLL -Z (byte 0x18) i inmatningsfilen. Detta är ett äldre läge från tidiga DOS-dagar då katalogen inte registrerade längden på filen och så beräknades fillängden baserat på antalet 512 byte sektorer. Om du kan säga till patch att öppna filen i binärt läge, bör den inte ’ inte ha detta fel.

    Lämna ett svar

    Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *