Verschil tussen twee vergelijkbare grote onbewerkte binaire bestanden

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 hele abc2 -bestand opnieuw te uploaden (het zou weer een paar uur duren!), en abc2 opnieuw te maken op de verre server van alleen abc en patch.

  • Lokaal, in plaats van 8 GB te verspillen aan back-up van zowel abc als abc2, kon ik alleen opslaan abc + 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

  • Heel erg bedankt @Kusalananda, het ‘ is geweldig! PS: rsync --read-batch=abc-diff ${1:-abc} (automatisch gegenereerd .sh-script) gaf remote destination is not allowed with --read-batch rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2], maar rsync --read-batch=abc-diff abc werkte met succes.Wat is het verschil tussen deze twee vergelijkbare commandos?
  • 2/2 Is er een manier om abc als invoer te nemen, pas de patch toe diff-abc met --read-batch maar niet wijzigen abc ” op zijn plaats “, maar liever uitvoeren naar een nieuw bestand abc3? (indien mogelijk allemaal met rsync, zonder piping, zodat het gemakkelijk zal werken onder Linux en Windows die ook rsync.exe beschikbaar heeft)
  • @Basj De commandos zouden verschillende dingen doen als $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 dan abc in plaats van “. Ik ‘ ga ervan uit dat $1 een waarde had toen je het probeerde, mogelijk iets dat het als een externe bestemmingsadres.
  • @Basj I ‘ ben niet helemaal zeker of dit mogelijk is, maar ik ‘ ll kijk morgen na het slapen.
  • Bedankt voor je antwoord over ${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 aangezien rsync --read-batch=abc-diff abc werkt 🙂

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 en mypatch abc patchfile > abc3) ongeacht de grootte. En als ik in stukken van 128 MB hak, wat gebeurt er dan als de eerste 1 GB van abc == de laatste (achterlopende) 1 GB van abc2 ? Wanneer we ‘ abc-first128mb vergelijken met abc2-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 en abc2. Toen probeerde ik diff -ua abc abc2 > patch, daarna kopieerde ik abc naar abc3 en ik probeerde abc2 dankzij abc3 en patch: patch abc3 < patch, maar het werkte niet: aan het einde was abc3 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 gegeven abc en patch?
  • 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.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *