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 plikabc2
(znowu zajmie to kilka godzin!) i ponownie utworzyćabc2
na odległym serwer tylko zabc
ipatch
. -
Lokalnie, zamiast marnować 8 GB na tworzenie kopii zapasowych zarówno
abc
, jak iabc2
, mogłem zapisać tylkoabc
+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]
, alersync --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 modyfikowaniaabc
” w miejscu „, ale raczej wyjście do nowego plikuabc3
? (jeśli to możliwe, wszystko zrsync
, 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żyjabc
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
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
iabc2
. Następnie wypróbowałemdiff -ua abc abc2 > patch
, a potem skopiowałemabc
doabc3
i próbowałem odzyskaćabc2
dziękiabc3
ipatch
:patch abc3 < patch
, ale to nie zadziałało: na końcuabc3
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 tylkoabc
ipatch
? - 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.
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).mydiff abc abc2 > patchfile
imypatch abc patchfile > abc3
) niezależnie od rozmiaru. Co się stanie, jeśli podzielę na 128 MB fragmenty, jeśli pierwszy 1 GB zabc
== ostatni (końcowy) 1 GB zabc2
? Kiedy ' porównujemyabc-first128mb
zabc2-first128mb
, żadne dopasowanie nie zostanie znalezione, więc może nie być wydajne?