Rozdíl dvou podobných velkých nezpracovaných binárních souborů

Řekněme, že mám 4 GB soubor abc místní počítač. Nahrál jsem to na vzdálený server přes SFTP, trvalo to několik hodin.

Nyní jsem lokálně mírně upravil soubor (maximálně asi 50 MB, ale ne po sobě jdoucích bajtů), a uložil jsem jej do abc2. Původní soubor abc jsem si také ponechal v místním počítači.

Jak vypočítat binární rozdíl abc a abc2?

Aplikace:

  • Mohu odeslat pouze soubor patch (pravděpodobně max. 100 MB) vzdálený server, namísto opětovného načtení celého abc2 souboru (bude to trvat znovu několik hodin!), a znovu vytvořte abc2 na vzdáleném serveru server pouze z abc a patch.

  • Lokálně bych místo plýtvání 8 GB zálohováním abc a abc2 mohl uložit pouze abc + patch, takže by to trvalo < pouze 4100 MB.

Jak na to?

PS: pro text znám diff, ale tady hledám něco, co by fungovalo pro jakýkoli surový binární formát, mohly by to být soubory zip nebo spustitelné soubory nebo dokonce jiné typy souborů.

PS2: Pokud je to možné, nechci použít rsync; Vím, že dokáže efektivně replikovat změny mezi 2 počítači (ne znovu odesílat data, která se nezměnila), ale tady opravdu chci mít soubor patch, který je později reprodukovatelný, pokud Mám abc a patch.

odpověď

Pro druhou aplikaci / problém bych místo pokusu použil deduplikační zálohovací program jako restic nebo borgbackup pro ruční sledování „oprav“ nebo rozdílů. Zálohovací program restic umožňuje zálohovat adresáře z více počítačů do stejného úložiště záloh a deduplikovat tak data zálohy mezi fragmenty souborů z jednotlivých počítačů i mezi nimi. (Nemám žádné uživatelské zkušenosti s borgbackup, takže o tomto programu nemohu nic říci.)

Výpočet a uložení rozdílu abc a abc2 lze vytvořit pomocí rsync.

Toto je příklad s abc a abc2 s 153 MB. Soubor abc2 byl změněn přepsáním prvních 2,3 MB souboru s některými dalšími údaji:

 $ 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  

Vytvoříme oprava pro transformaci abc na abc2 a nazývání 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  

Vygenerovaný soubor abc-diff je skutečný rozdíl (váš „soubor opravy“), zatímco abc-diff.sh jekrátký skript prostředí, který pro vás rsync vytvoří:

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

Tento skript upraví abc tak, aby se stal identickým s abc2, vzhledem k souboru abc-diff:

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

Soubor abc-diff nyní lze přenést kamkoli jinde máte abc. Pomocí příkazu rsync --read-batch=abc-diff abc byste opravu aplikovali na soubor abc a transformovali jeho obsah tak, aby byl stejný jako abc2 soubor v systému, kde jste vytvořili rozdíl.

Opětovné použití opravy se zdá být bezpečné. Neexistují žádné chybové zprávy ani se nemění obsah souboru (kontrolní součet MD5 se nemění).

Upozorňujeme, že pokud nevytvoříte explicitní „reverzní opravu“, neexistuje způsob, jak aplikaci snadno vrátit zpět. opravy.


Také jsem otestoval zápis úpravy 2,3 MB na nějaké jiné místo v datech abc2, o kousek dál (asi 50 MB), stejně jako na začátku. Vygenerovaná „oprava“ byla velká 4,6 MB, což naznačuje, že v opravě byly uloženy pouze upravené bity.

Komentáře

  • Mnohokrát děkujeme @Kusalananda, je to ‚ skvělé! PS: rsync --read-batch=abc-diff ${1:-abc} (automaticky generovaný skript .sh) dal remote destination is not allowed with --read-batch rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2], ale rsync --read-batch=abc-diff abc fungoval úspěšně.Jaký je rozdíl mezi těmito dvěma podobnými příkazy?
  • 2/2 Existuje způsob, jak vzít abc jako vstup, použít patch diff-abc s --read-batch, ale nemění abc “ na místě „, ale spíše výstup do nového souboru abc3? (pokud je to možné vše s rsync, bez použití potrubí, takže to bude fungovat snadno na Linuxu i Windows, který má také rsync.exe k dispozici)
  • @Basj Příkazy by dělaly různé věci, kdyby $1 měl hodnotu. ${1:-abc} znamená “ použít první poziční parametr ($1), pokud ‚ je prázdný nebo nedefinovaný. V případě, že je ‚ prázdný nebo nedefinovaný, použijte místo toho abc „. ‚ m za předpokladu, že $1 měl hodnotu, když jste to zkusili, možná něco, co to interpretovalo jako vzdálená cílová adresa.
  • @Basj I ‚ si nejsem úplně jistý, zda je to možné, ale ‚ ll podívejte se zítra po spánku.
  • Děkujeme za odpověď týkající se ${1:-abc}. Pravděpodobně se to nezdařilo, protože jsem to zkusil na Windows (‚ m používám rsync jak na Linuxu pro můj vzdálený server, tak i lokálně Windows). Ale ‚ je perfektní, protože rsync --read-batch=abc-diff abc funguje 🙂

Odpověď

Jak vypočítat binární rozdíl abc a abc2?

Použití bsdiff / bspatch nebo xdelta a dalších.

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

Je však třeba si uvědomit tato upozornění z manuálových stránek:

  • bsdiff používá paměť rovnou 17násobku velikosti oldfile a vyžaduje absolutní minimální velikost pracovní sady 8krát větší než oldfile .
  • bspatch používá paměť rovnou velikosti oldfile plus velikosti newfile , ale může tolerovat velmi malou pracovní sadu bez dramatické ztráty výkonu.

Komentáře

  • Můžete mi ukázat nějaký příklad?
  • Děkuji za odpověď. bsdiff uses memory equal to 17 times the size of oldfile takže to obvykle ‚ obvykle nefunguje pro 4GB soubory (alespoň na mém 8GB RAM stroji).
  • @Basj Je možné rozřezat 4GB soubor na menší (řekněme každý 128MB) a dělat jednotlivé delty. To by mohlo být zabaleno do skriptu. chopped-bsdiff: sekání souborů, párování bsdiffů, jejich tarování do archivu. chopped-bspatch: číst párové patche z archivu, aplikovat na bloky vstupního souboru, catenovat výstup.
  • @Kaz vidím, ale ‚ více hledám nástroj připravený k použití, který lze vyvolat na 1 řádku (mydiff abc abc2 > patchfile a mypatch abc patchfile > abc3) bez ohledu na velikost. Pokud také nasekám na 128 MB bloky, co se stane, když první 1 GB abc == poslední (koncové) 1 GB abc2 ? Když ‚ porovnáme abc-first128mb s abc2-first128mb, nebude nalezena žádná shoda, takže nemusí být efektivní?

Odpověď

Zkusili jste jen vynucení diff zacházet se soubory jako s textem:

diff -ua abc abc2 

Jak je vysvětleno zde .

  • -u výstup NUM (výchozí 3) řádky sjednoceného kontextu
  • -a zacházet se všemi soubory jako s textem

To by vám mělo dát opravu. Nevýhodou je, že „řádky“ mohou být poměrně dlouhé a to by mohlo nafouknout náplast.

Komentáře

  • Jejda, jo, ‚ ve skutečnosti n nechce. ‚ Mám zájem vědět, jestli to funguje, protože si ‚ nejsem jistý, jak dlouho “ lines “ bude.
  • Děkujeme za váš komentář! Vytvořil jsem dva velmi podobné soubory 256 MB abc a abc2. Pak jsem zkusil diff -ua abc abc2 > patch, potom jsem zkopíroval abc do abc3 a pokusil jsem se obnovit abc2 díky abc3 a patch: patch abc3 < patch, ale nefungovalo to: na konci abc3 byl místo 256 MB pouze 1 kB. Máte nějaký nápad?
  • Hmmm, nejste si jisti, co se stalo. Právě jsem to udělal na svém stroji a fungovalo to lépe, než jsem čekal.Vzal jsem soubor 382M, který byl náhodná celá čísla zapsaná binárně do souboru. Změnil jsem v něm 3 bajty a udělal diff a patch a fungovalo to. Výsledné soubory byly stejné jako md5sum.
  • Pokud velký soubor nemá žádný bajt 0x0a, tj. Nový řádek, nebo jen velmi málo, domnívám se, že by to nebylo ‚ nefunguje tak dobře, bylo by zajímavé otestovat.
  • Určitě. Vzdělaný odhad můžete udělat na binárním souboru s wc -l, který bude hledat konce řádků a podle mých zkušeností běží velmi rychle. Očekával bych, že na libovolném binárním souboru to bude fungovat docela dobře. Například na svém stroji jsem našel 252M mp4, který měl 1,2 milionu “ řádků “ a 59M .deb které měly přibližně 230 kB, takže průměrné “ řádky “ byly méně než 220 bajtů a 258 bajtů. Nechápu ‚, proč by se tyto soubory lišily od ostatních, ale určitě byste měli smůlu. V praxi mám podezření, že by to fungovalo docela dobře, a pokud ne, je to stále ‚ stále zábavný hack.

Odpověď

Použijte xdelta , byla vytvořena přesně pro tento typ použití. Na základě VCDIFF (RFC 3284) v nejnovějších verzích.

Komentáře

  • Odkaz nefunguje (existuje jiná adresa URL?). Můžete také přidat příklad na několik řádků, který ukazuje, jak: 1) vypočítat soubor diff patch a 2) obnovit abc2 , uvedeno pouze abc a patch?
  • Omlouváme se, opravená URL
  • děkuji @vonbrand . Máte takový příklad?

Odpověď

Doplňky k dalším odpovědím podle mých testů:

S diff

jsem vytvořil dva velmi podobné 256 MB soubory abc a abc2. Poté vytvořme soubor rozdílu:

diff -ua abc abc2 > abc-abc2.diff 

Nyní se pokusme obnovit abc2 díky původní abc soubor a abc-abc2.diff:

cp abc abc3 patch abc3 < abc-abc2.diff 

nebo

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

nebo

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

Funguje na systému Linux. Také jsem vyzkoušel Windows (patch.exe a diff.exe jsou také k dispozici), ale z neznámého důvodu se to nezdařilo: vyprodukovaný soubor abc3 má pouze 1 kB místo 256 MB (I “ Aktualizuji tuto odpověď později zde).

S rsync

Jak je uvedeno v přijaté odpovědi, toto funguje:

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

s rdiff

Jak je podrobně uvedeno v tomto odpověď , toto je také řešení:

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

Testováno také na Windows s rdiff.exe z zde a funguje to.

Komentáře

  • Já ‚ hádám, že oprava v systému Windows selhala, protože načítal vstupní soubor v režimu “ text „, který signalizuje konec souboru, když narazí na KONTROLU -Z (bajt 0x18) ve vstupním souboru. Toto je starší režim z prvních dnů systému DOS, kdy adresář nezaznamenával délku soubor a tak byla vypočítána délka souboru na základě počtu 512 bajtových sektorů. Pokud můžete říct patch, aby soubor otevřel v binárním režimu, neměla by ‚ tuto chybu mít.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *