Laten we zeggen dat ik een bestand van 4 GB abc
op mijn lokale computer. Ik heb het geüpload naar een verre server via SFTP, het heeft een paar uur geduurd.
Nu heb ik het bestand lokaal enigszins gewijzigd (waarschijnlijk maximaal 50 MB, maar geen opeenvolgende bytes in dit bestand), en bewaarde het in abc2
. Ik bewaarde ook het originele bestand abc
op mijn lokale computer.
Hoe bereken je een binaire diff van abc
en abc2
?
Toepassingen:
-
Ik kon alleen een
patch
-bestand (waarschijnlijk max 100 MB) sturen naar de verre server, in plaats van het heleabc2
-bestand opnieuw te uploaden (het zou weer een paar uur duren!), enabc2
opnieuw te maken op de verre server van alleenabc
enpatch
. -
Lokaal, in plaats van 8 GB te verspillen aan back-up van zowel
abc
alsabc2
, kon ik alleen opslaanabc
+patch
, dus het zou slechts < 4100 MB nodig hebben.
Hoe dit te doen?
PS: voor tekst weet ik diff
, maar hier ben ik op zoek naar iets dat zou kunnen werken voor elk onbewerkt binair formaat, het kunnen zip-bestanden of uitvoerbare bestanden of zelfs andere bestandstypen zijn.
PS2: Indien mogelijk, wil ik ; Ik weet dat het wijzigingen tussen 2 computers op een efficiënte manier kan repliceren (gegevens die niet opnieuw zijn verzonden), maar hier wil ik echt een patch
-bestand hebben, dat later kan worden gereproduceerd als Ik heb zowel abc
als patch
.
Antwoord
Voor de tweede toepassing / uitgave zou ik een ontdubbelings back-upprogramma zoals restic
of borgbackup
gebruiken, in plaats van te proberen om handmatig “patches” of diffs bij te houden. Met het restic
back-upprogramma kunt u een back-up maken van mappen van meerdere machines naar dezelfde back-uprepository, waarbij de back-upgegevens zowel tussen fragmenten van bestanden van een individuele machine als tussen machines worden ontdubbeld. (Ik heb geen gebruikerservaring met borgbackup
, dus ik kan “niets over dat programma zeggen.)
Een diff van de abc
en abc2
bestanden kunnen worden aangemaakt met rsync
.
Dit is een voorbeeld waarbij abc
en abc2
153 MB is. Het bestand abc2
is gewijzigd door de eerste 2,3 MB van het bestand met wat andere gegevens:
$ 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
We creëren out patch voor het transformeren van abc
in abc2
en noem het 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
Het gegenereerde bestand abc-diff
is de feitelijke diff (uw “patchbestand”), terwijl abc-diff.sh
iseen kort shell-script dat rsync
voor u maakt:
$ cat abc-diff.sh rsync --read-batch=abc-diff ${1:-abc}
Dit script wijzigt abc
zodat het identiek wordt aan abc2
, gezien het bestand abc-diff
:
$ md5sum abc abc2 be00efe0a7a7d3b793e70e466cbc53c6 abc 3decbde2d3a87f3d954ccee9d60f249b abc2 $ sh abc-diff.sh $ md5sum abc abc2 3decbde2d3a87f3d954ccee9d60f249b abc 3decbde2d3a87f3d954ccee9d60f249b abc2
Het bestand abc-diff
kan nu worden overgebracht naar eender waar abc
. Met het commando rsync --read-batch=abc-diff abc
, zou je de patch toepassen op het bestand abc
, waarbij je de inhoud ervan verandert in hetzelfde als de abc2
bestand op het systeem waarop u de diff heeft aangemaakt.
Het lijkt veilig om de patch een tweede keer opnieuw toe te passen. Er zijn geen foutmeldingen en de inhoud van het bestand verandert ook niet (de MD5-checksum verandert niet).
Merk op dat tenzij je een expliciete “reverse patch” maakt, er geen manier is om de applicatie gemakkelijk ongedaan te maken van de patch.
Ik heb ook getest het schrijven van de 2,3 MB-wijziging naar een andere plaats in de abc2
-gegevens, een beetje verder in (op ongeveer 50 MB), evenals aan het begin. De gegenereerde “patch” was 4,6 MB groot, wat suggereert dat alleen de gewijzigde bits in de patch waren opgeslagen.
Opmerkingen
Antwoord
Hoe bereken je een binaire diff van abc en abc2?
Met bsdiff / bspatch of xdelta en anderen.
$ bsdiff older newer patch.bin # patch.bin is created [...] $ bspatch older newer patch.bin # newer is created
Deze waarschuwingen van de man-paginas moeten echter worden opgemerkt:
-
bsdiff
gebruikt geheugen gelijk aan 17 keer de grootte van oldfile , en vereist een absoluut minimum werkset grootte van 8 keer de grootte van oldfile . -
bspatch
gebruikt geheugen gelijk aan de grootte van oldfile plus de grootte van newfile , maar kan een zeer kleine werkset verdragen zonder dramatisch prestatieverlies.
Reacties
- Kunt u mogelijk een voorbeeld laten zien?
- Bedankt voor uw antwoord.
bsdiff uses memory equal to 17 times the size of oldfile
dus dit ‘ werkt meestal niet voor bestanden van 4 GB (tenminste op mijn 8 GB RAM-machine). - @Basj Wat mogelijk is, is om het bestand van 4 GB in kleinere bestanden te hakken (zeg 128 MB elk) en individuele deltas te maken. Dit zou in een script kunnen worden verpakt. chopped-bsdiff: hak de bestanden in stukken, voer paarsgewijze bsdiffs uit, voeg ze toe aan een archief. chopped-bspatch: lees paarsgewijze patches uit archief, pas toe op brokken invoerbestand, catenate output.
- @Kaz Ik begrijp het, maar ik ‘ ben meer op zoek naar een gebruiksklare tool die kan worden aangeroepen in 1 regel (
mydiff abc abc2 > patchfile
enmypatch abc patchfile > abc3
) ongeacht de grootte. En als ik in stukken van 128 MB hak, wat gebeurt er dan als de eerste 1 GB vanabc
== de laatste (achterlopende) 1 GB vanabc2
? Wanneer we ‘abc-first128mb
vergelijken metabc2-first128mb
, wordt er geen overeenkomst gevonden, dus is misschien niet efficiënt?
Answer
Heb je geprobeerd diff
om de bestanden als tekst te behandelen:
diff -ua abc abc2
Zoals hier uitgelegd.
-
-u
output NUM (standaard 3) regels van verenigde context -
-a
behandel alle bestanden als tekst
Dit zou je een patch moeten opleveren. Het nadeel hiervan is dat de “lijnen” behoorlijk lang kunnen zijn en dat de patch kan opzwellen.
Reacties
- Oeps, ja, je doet ‘ Ik wil eigenlijk de
n
. Ik ‘ m benieuwd of het werkt, aangezien ik ‘ m niet zeker weet hoe lang de ” lines ” zal worden. - Bedankt voor je reactie! Ik heb twee zeer vergelijkbare bestanden van 256 MB gemaakt
abc
enabc2
. Toen probeerde ikdiff -ua abc abc2 > patch
, daarna kopieerde ikabc
naarabc3
en ik probeerdeabc2
dankzijabc3
enpatch
:patch abc3 < patch
, maar het werkte niet: aan het einde wasabc3
slechts 1 KB in plaats van 256 MB. Enig idee? - Hmmm, niet zeker wat er is gebeurd. Ik deed het gewoon op mijn machine en het werkte beter dan ik had verwacht.Ik nam een 382M-bestand dat bestond uit willekeurige gehele getallen die in binair bestand naar een bestand waren geschreven. Ik veranderde er 3 bytes in en deed de diff en patch en het werkte. De resulterende bestanden waren gelijk aan md5sum.
- Als een groot bestand geen byte
0x0a
heeft, dwz een nieuwe regel, of heel weinig, dan vermoed ik dat het niet ‘ werkt niet zo goed, het zou interessant zijn om te testen. - Oh zeker. Je kunt een weloverwogen schatting maken van een binair bestand met
wc -l
dat naar regeleinden zoekt en naar mijn ervaring loopt het erg snel. Ik zou verwachten dat het op een willekeurig binair bestand redelijk goed zou werken. Op mijn computer vond ik bijvoorbeeld een 252M mp4 met 1,2 miljoen ” regels “, en een 59M.deb
die ongeveer 230k had, dus gemiddeld ” regels ” van respectievelijk minder dan 220 bytes en 258 bytes. Ik begrijp niet ‘ waarom deze bestanden zo anders zouden zijn dan andere, maar je zou zeker pech kunnen krijgen. In de praktijk vermoed ik dat het redelijk goed zou werken en zo niet is het ‘ nog steeds een leuke hack.
Antwoord
Gebruik xdelta , het is precies voor dit soort gebruik gemaakt. Gebaseerd op VCDIFF (RFC 3284) in de laatste versies.
Reacties
- De link werkt niet (is er een andere URL?). Kunt u ook in een paar regels een voorbeeld toevoegen om te laten zien hoe u: 1) het bestand diff
patch
berekent, en 2)abc2
herstelt , alleen gegevenabc
enpatch
? - Sorry, vaste URL
- Bedankt @vonbrand . Zou je zon voorbeeld hebben?
Antwoord
Aanvullingen op andere antwoorden volgens mijn tests:
Met diff
Ik heb twee zeer vergelijkbare bestanden van 256 MB gemaakt abc
en abc2
. Laten we vervolgens het diff-bestand maken:
diff -ua abc abc2 > abc-abc2.diff
Laten we nu proberen abc2
te herstellen dankzij de origineel abc
bestand en abc-abc2.diff
:
cp abc abc3 patch abc3 < abc-abc2.diff
of
cp abc abc3 patch abc3 -i abc-abc2.diff
of
patch abc -i abc-abc2.diff -o abc3
Het werkt op Linux. Ik heb het ook geprobeerd op Windows (patch.exe en diff.exe zijn ook beschikbaar), maar om een onbekende reden is het mislukt: het geproduceerde abc3
-bestand is slechts 1 KB in plaats van 256 MB (I ” Ik zal dit antwoord later hier bijwerken).
Met rsync
Zoals gedetailleerd in het geaccepteerde antwoord, werkt dit:
rsync --only-write-batch=abc-abc2-diff abc2 abc cp abc abc3 rsync --read-batch=abc-abc2-diff abc3
Met rdiff
Zoals beschreven in dit antwoord , dit is ook een oplossing:
rdiff signature abc abc-signature rdiff delta abc-signature abc2 abc-abc2-delta rdiff patch abc abc-abc2-delta abc3
Ook getest op Windows met rdiff.exe van hier en het werkt.
Reacties
- Ik ‘ vermoed dat patch mislukt op Windows omdat het het invoerbestand aan het lezen was in ” text ” modus die het einde van het bestand aangeeft wanneer het een CONTROL tegenkomt -Z (byte 0x18) in het invoerbestand. Dit is een legacy-modus uit vroege DOS-dagen toen de directory de lengte van het bestand en dus werd de bestandslengte berekend op basis van het aantal sectoren van 512 bytes. Als je
patch
kunt vertellen om het bestand in binaire modus te openen, mag ‘ deze fout niet hebben.
rsync --read-batch=abc-diff ${1:-abc}
(automatisch gegenereerd .sh-script) gafremote destination is not allowed with --read-batch
rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2]
, maarrsync --read-batch=abc-diff abc
werkte met succes.Wat is het verschil tussen deze twee vergelijkbare commandos?abc
als invoer te nemen, pas de patch toediff-abc
met--read-batch
maar niet wijzigenabc
” op zijn plaats “, maar liever uitvoeren naar een nieuw bestandabc3
? (indien mogelijk allemaal metrsync
, zonder piping, zodat het gemakkelijk zal werken onder Linux en Windows die ookrsync.exe
beschikbaar heeft)$1
een waarde had.${1:-abc}
betekent ” gebruik de eerste positionele parameter ($1
) tenzij deze ‘ is leeg of niet gedefinieerd. In het geval dat het ‘ leeg of ongedefinieerd is, gebruik danabc
in plaats van “. Ik ‘ ga ervan uit dat$1
een waarde had toen je het probeerde, mogelijk iets dat het als een externe bestemmingsadres.${1:-abc}
. Het is waarschijnlijk mislukt omdat ik het op Windows heb geprobeerd (ik ‘ m gebruikmakend van rsync zowel op Linux voor mijn verre server als Windows lokaal). Maar het ‘ is perfect aangezienrsync --read-batch=abc-diff abc
werkt 🙂