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 helaabc2
-filen (det skulle ta några timmar igen!) och återskapaabc2
på den avlägsna endast frånabc
ochpatch
. -
Lokalt, istället för att slösa bort 8 GB för att säkerhetskopiera både
abc
ochabc2
, kunde jag bara sparaabc
+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
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
ochmypatch abc patchfile > abc3
) oavsett storlek. Om jag hackar i 128 MB bitar, vad händer om den första 1 GBabc
== den sista (efterföljande) 1 GBabc2
? När vi ’ jämförabc-first128mb
medabc2-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.
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é? 0x0a
, dvs newline, eller mycket få, misstänker jag att den inte skulle ’ fungerar inte så bra, det skulle vara intressant att testa. 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ällerabc2
, ges endastabc
ochpatch
? - 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.
rsync --read-batch=abc-diff ${1:-abc}
(automatiskt genererat .sh-skript) gavremote destination is not allowed with --read-batch
rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2]
, menrsync --read-batch=abc-diff abc
fungerade framgångsrikt.Vad är skillnaden mellan dessa två liknande kommandon?abc
som inmatning, applicera plåstretdiff-abc
med--read-batch
men ändrar inteabc
” på plats ”, utan snarare mata ut till en ny filabc3
? (om möjligt allt medrsync
, utan piping, så att det fungerar enkelt på Linux såväl som Windows som också harrsync.exe
tillgängligt)$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ändabc
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.${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 eftersomrsync --read-batch=abc-diff abc
fungerar 🙂