Różnica między dwoma podobnymi dużymi nieprzetworzonymi plikami binarnymi

Powiedzmy, że mam 4 GB plik abc na moim lokalny komputer. Wgrałem go na odległy serwer przez SFTP, zajęło to kilka godzin.

Lokalnie nieznacznie zmodyfikowałem plik (prawdopodobnie maksymalnie 50 MB, ale nie kolejne bajty w tym pliku), i zapisałem go w abc2. Zachowałem również oryginalny plik abc na moim lokalnym komputerze.

Jak obliczyć różnicę binarną abc i abc2?

Aplikacje:

  • Mogłem wysłać tylko plik patch (prawdopodobnie maks. 100 MB) do odległy serwer, zamiast przesyłać ponownie cały plik abc2 (znowu zajmie to kilka godzin!) i ponownie utworzyć abc2 na odległym serwer tylko z abc i patch.

  • Lokalnie, zamiast marnować 8 GB na tworzenie kopii zapasowych zarówno abc, jak i abc2, mogłem zapisać tylko abc + patch, więc zajmie tylko < 4100 MB.

Jak to zrobić?

PS: w przypadku tekstu wiem, diff, ale tutaj szukam coś, co mogłoby działać dla dowolnego surowego formatu binarnego, mogą to być pliki zip, pliki wykonywalne lub nawet inne typy plików.

PS2: Jeśli to możliwe, nie chcę używać rsync; Wiem, że może efektywnie replikować zmiany między 2 komputerami (bez ponownego wysyłania danych, które się nie zmieniły), ale tutaj naprawdę chcę mieć plik patch, który można odtworzyć później, jeśli Mam zarówno abc, jak i patch.

Odpowiedź

W przypadku drugiej aplikacji / problemu użyłbym programu do usuwania duplikatów, takiego jak restic lub borgbackup, zamiast próbować aby ręcznie śledzić „łaty” lub różnice. Program do tworzenia kopii zapasowych restic umożliwia tworzenie kopii zapasowych katalogów z wielu komputerów w tym samym repozytorium kopii zapasowych, deduplikując dane kopii zapasowej zarówno wśród fragmentów plików z pojedynczego komputera, jak i między komputerami. (Nie mam doświadczenia użytkownika z borgbackup, więc nie mogę nic powiedzieć o tym programie.)

Obliczanie i przechowywanie różnicy abc i abc2 można wykonać za pomocą rsync.

To jest przykład przy abc i abc2 o rozmiarze 153 MB. Plik abc2 został zmodyfikowany przez nadpisanie pierwsze 2,3 MB pliku z innymi danymi:

 $ 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  

Tworzymy łatka do przekształcania abc w abc2 i nazwij ją 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  

Wygenerowany plik abc-diff to rzeczywisty plik różnicowy (Twój „plik poprawki”), podczas gdy abc-diff.sh jestkrótki skrypt powłoki, który rsync tworzy dla Ciebie:

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

Ten skrypt modyfikuje abc, dzięki czemu staje się identyczny z abc2, biorąc pod uwagę plik abc-diff:

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

Plik abc-diff można teraz przenieść w inne miejsce abc. Za pomocą polecenia rsync --read-batch=abc-diff abc można zastosować poprawkę do pliku abc, przekształcając jego zawartość tak, aby była taka sama jak abc2 w systemie, w którym utworzyłeś różnicę.

Ponowne zastosowanie łatki wydaje się bezpieczne. Nie ma komunikatów o błędach ani nie zmienia się zawartość pliku (suma kontrolna MD5 nie zmienia się).

Zauważ, że jeśli nie utworzysz jawnej „odwrotnej łatki”, nie ma możliwości łatwego cofnięcia aplikacji poprawki.


Testowałem również zapisywanie modyfikacji 2,3 MB w innym miejscu w danych abc2, nieco dalej (około 50 MB), jak również na początku. Wygenerowana „łatka” miała wielkość 4,6 MB, co sugeruje, że w łacie były przechowywane tylko zmodyfikowane bity.

Komentarze

  • Wielkie dzięki @Kusalananda, to ' super! PS: rsync --read-batch=abc-diff ${1:-abc} (automatycznie wygenerowany skrypt .sh) dał 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 działało pomyślnie.Jaka jest różnica między tymi dwoma podobnymi poleceniami?
  • 2/2 Czy istnieje sposób, aby wziąć abc jako dane wejściowe, zastosować poprawkę diff-abc z --read-batch, ale bez modyfikowania abc ” w miejscu „, ale raczej wyjście do nowego pliku abc3? (jeśli to możliwe, wszystko z rsync, bez potoku, dzięki czemu będzie łatwo działać zarówno w systemie Linux, jak i Windows, który ma również rsync.exe dostępny)
  • @Basj Polecenia zrobiłyby różne rzeczy, gdyby $1 miało wartość. ${1:-abc} oznacza ” użyj pierwszego parametru pozycyjnego ($1), chyba że jest pusty lub niezdefiniowany. W przypadku, gdy ' jest pusty lub niezdefiniowany, użyj abc zamiast „. ' m zakładam, że $1 miał wartość podczas próby, prawdopodobnie coś, co zinterpretował jako zdalny adres docelowy.
  • @Basj I ' Nie jestem do końca pewien, czy jest to możliwe, ale ' ll zajrzyj jutro po śnie.
  • Dziękuję za odpowiedź na temat ${1:-abc}. Prawdopodobnie się nie udało, ponieważ wypróbowałem go w systemie Windows (' m używam rsync zarówno w systemie Linux dla mojego odległego serwera, jak i Windows lokalnie). Ale to ' jest idealne, ponieważ rsync --read-batch=abc-diff abc działa 🙂

Odpowiedź

Jak obliczyć binarną różnicę abc i abc2?

Używając bsdiff / bspatch lub xdelta i innych.

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

Należy jednak odnotować następujące ostrzeżenia ze stron podręcznika:

  • bsdiff wykorzystuje pamięć równą 17-krotnemu rozmiarowi stary plik i wymaga absolutnego minimalnego rozmiaru zestawu roboczego 8 razy większego niż stary plik .
  • bspatch używa pamięci równej rozmiarowi starego pliku plus rozmiar nowego pliku , ale może tolerować bardzo mały zestaw roboczy bez dramatycznej utraty wydajności.

Komentarze

  • Czy mógłbyś pokazać przykład?
  • Dziękuję za odpowiedź. bsdiff uses memory equal to 17 times the size of oldfile, więc wygrał ' t zwykle działa dla plików 4 GB (przynajmniej na moim komputerze z 8 GB RAM).
  • @Basj Możliwe jest podzielenie pliku 4 GB na mniejsze (powiedzmy po 128 MB każdy) i wykonanie poszczególnych delt. Można to umieścić w skrypcie. chopped-bsdiff: posiekaj pliki, wykonaj parowanie bsdiffs, tar je do archiwum. chopped-bspatch: czytaj parami łaty z archiwum, zastosuj do fragmentów pliku wejściowego, wyłapuj dane wyjściowe.
  • @Kaz widzę, ale ' więcej szukam gotowe do użycia narzędzie, które można wywołać w 1 linii (mydiff abc abc2 > patchfile i mypatch abc patchfile > abc3) niezależnie od rozmiaru. Co się stanie, jeśli podzielę na 128 MB fragmenty, jeśli pierwszy 1 GB z abc == ostatni (końcowy) 1 GB z abc2 ? Kiedy ' porównujemy abc-first128mb z abc2-first128mb, żadne dopasowanie nie zostanie znalezione, więc może nie być wydajne?

Odpowiedz

Czy próbowałeś wymusić tylko diff, aby traktować pliki jako tekst:

diff -ua abc abc2 

Jak wyjaśniono tutaj .

  • -u wyjście NUM (domyślnie 3) wiersze ujednoliconego kontekstu
  • -a traktuj wszystkie pliki jako tekst

To powinno dać ci łatkę. Wadą tego jest to, że „linie” mogą być dość długie, a to może nadmuchać łatkę.

Komentarze

  • Ups, tak, nie ' tak naprawdę chcesz n. ' interesuje mnie, czy to działa tak, jak ' Nie wiem, jak długo ” linie ” będą.
  • Dziękujemy za komentarz! Utworzyłem dwa bardzo podobne pliki 256 MB abc i abc2. Następnie wypróbowałem diff -ua abc abc2 > patch, a potem skopiowałem abc do abc3 i próbowałem odzyskać abc2 dzięki abc3 i patch: patch abc3 < patch, ale to nie zadziałało: na końcu abc3 miał tylko 1 KB zamiast 256 MB. Masz jakiś pomysł?
  • Hmmm, nie wiem, co się stało. Po prostu zrobiłem to na mojej maszynie i zadziałało lepiej, niż się spodziewałem.Wziąłem plik 382M, który zawierał losowe liczby całkowite zapisane binarnie do pliku. Zmieniłem w nim 3 bajty i zrobiłem różnicę i łatkę i zadziałało. Wynikowe pliki miały sumę md5 równą.
  • Jeśli duży plik nie ma bajtów 0x0a, tj. Znak nowej linii lub bardzo niewiele, podejrzewam, że nie ' nie działa tak dobrze, byłoby interesujące przetestować.
  • Och, na pewno. Możesz zgadnąć plik binarny za pomocą wc -l, który będzie szukał podziałów wierszy i, z mojego doświadczenia, działa bardzo szybko. Spodziewałbym się, że na arbitralnym pliku binarnym będzie działać całkiem dobrze. Na przykład na moim komputerze znalazłem 252 mln mp4 z 1,2 mln ” linii ” i 59 mln .deb, który miał około 230 KB, więc średnio ” wiersze ” miały odpowiednio mniej niż 220 bajtów i 258 bajtów. Nie ' nie rozumiem, dlaczego te pliki byłyby tak różne od innych, ale na pewno możesz mieć pecha. W praktyce podejrzewam, że działałoby to całkiem nieźle, a jeśli nie, to ' to nadal fajny hack.

Odpowiedź

Użyj xdelta , został stworzony dokładnie do tego typu zastosowań. Oparty na VCDIFF (RFC 3284) w najnowszych wersjach.

Komentarze

  • Link nie działa (czy jest inny adres URL?). Możesz również dodać przykład w kilku wierszach, aby pokazać, jak: 1) obliczyć plik diff patch i 2) przywrócić abc2 , podane tylko abc i patch?
  • Przepraszamy, stały adres URL
  • Dzięki @vonbrand . Miałbyś taki przykład?

Odpowiedź

Uzupełnia inne odpowiedzi według moich testów:

Za pomocą diff

Utworzyłem dwa bardzo podobne pliki 256 MB abc i abc2. Następnie stwórzmy plik różnic:

diff -ua abc abc2 > abc-abc2.diff 

Teraz spróbujmy odzyskać abc2 dzięki oryginalny abc plik i abc-abc2.diff:

cp abc abc3 patch abc3 < abc-abc2.diff 

lub

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

lub

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

Działa w systemie Linux. Próbowałem również w systemie Windows (dostępne są również patch.exe i diff.exe), ale z nieznanego powodu nie powiodło się: utworzony plik abc3 ma tylko 1 KB zamiast 256 MB (I ” Zaktualizuj tę odpowiedź później tutaj).

Z rsync

Jak wyszczególniono w zaakceptowanej odpowiedzi, to działa:

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

Z rdiff

Jak opisano szczegółowo w odpowiedź , to też jest rozwiązanie:

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

Testowane również w systemie Windows z rdiff.exe z tutaj i działa.

Komentarze

  • I ' zgaduję, że poprawka nie powiodła się w systemie Windows, ponieważ czytał plik wejściowy w trybie ” tekst „, który sygnalizuje koniec pliku, gdy napotka KONTROLĘ -Z (bajt 0x18) w pliku wejściowym. Jest to starszy tryb z wczesnych dni DOS, kiedy katalog nie zapisywał długości plik, więc długość pliku została obliczona na podstawie liczby sektorów 512-bajtowych. Jeśli możesz powiedzieć patch, aby otworzył plik w trybie binarnym, nie powinien ' nie mieć tego błędu.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *