Lad os sige, at jeg har en 4 GB-fil abc
på min lokal computer. Jeg har uploadet den til en fjern server via SFTP, det tog et par timer.
Nu har jeg lidt ændret filen (sandsynligvis maksimalt 50 MB, men ikke på hinanden følgende byte i denne fil) lokalt, og gemte det i abc2
. Jeg gemte også den originale fil abc
på min lokale computer.
Sådan beregnes en binær diff på abc
og abc2
?
Applikationer:
-
Jeg kunne kun sende en
patch
-fil (sandsynligvis maks. 100 MB) til den fjerne server i stedet for at geninstallere heleabc2
filen (det ville tage et par timer igen!), og genskababc2
på den fjerne server kun fraabc
ogpatch
. -
Lokalt, i stedet for at spilde 8 GB til backup af både
abc
ogabc2
, kunne jeg kun gemmeabc
+patch
, så det tager kun < 4100 MB.
Hvordan gør man det?
PS: for tekst kender jeg diff
, men her leder jeg efter noget, der kunne fungere for ethvert rå binært format, det kunne være zip-filer eller eksekverbare filer eller endda andre filtyper.
PS2: Hvis det er muligt, vil jeg ikke bruge rsync
; Jeg ved, at det kan replikere ændringer mellem 2 computere på en effektiv måde (ikke videresende data, der ikke er ændret), men her vil jeg virkelig have en patch
-fil, der kan reproduceres senere, hvis Jeg har både abc
og patch
.
Svar
Til det andet program / problem vil jeg bruge et deduplicering af sikkerhedskopieringsprogram som restic
eller borgbackup
i stedet for at prøve for manuelt at holde styr på “patches” eller diffs. restic
sikkerhedskopieringsprogrammet giver dig mulighed for at sikkerhedskopiere mapper fra flere maskiner til det samme sikkerhedskopier og deduplicere sikkerhedskopidataene blandt fragmenter af filer fra en enkelt maskine såvel som mellem maskinen. (Jeg har ingen brugeroplevelse med borgbackup
, så jeg kan ikke sige noget om dette program.)
Beregning og lagring af en diff af abc
og abc2
filer kan gøres med rsync
.
Dette er et eksempel med abc
og abc2
153 MB. Filen abc2
er blevet ændret ved at overskrive første 2,3 MB af filen med nogle andre data:
$ 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
Vi opretter ud patch til at omdanne abc
til abc2
og kalde det 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
Den genererede fil abc-diff
er den faktiske diff (din “patch-fil”), mens abc-diff.sh
eret kort shell-script, som rsync
opretter til dig:
$ cat abc-diff.sh rsync --read-batch=abc-diff ${1:-abc}
Dette script ændrer abc
, så det bliver identisk med abc2
, givet filen abc-diff
:
$ md5sum abc abc2 be00efe0a7a7d3b793e70e466cbc53c6 abc 3decbde2d3a87f3d954ccee9d60f249b abc2 $ sh abc-diff.sh $ md5sum abc abc2 3decbde2d3a87f3d954ccee9d60f249b abc 3decbde2d3a87f3d954ccee9d60f249b abc2
Filen abc-diff
kunne nu overføres til hvor som helst du har abc
. Med kommandoen rsync --read-batch=abc-diff abc
anvender du patch til filen abc
og omdanner dens indhold til at være det samme som abc2
-fil på det system, hvor du oprettede diff.
Genanvendelse af programrettelsen en anden gang virker sikkert. Der er ingen fejlmeddelelser, og heller ikke ændres filens indhold (MD5-kontrolsummen ændres ikke.).
Bemærk, at medmindre du opretter en eksplicit “omvendt patch”, er der ingen måde at fortryde applikationen let af plasteret.
Jeg testede også at skrive 2,3 MB-modifikationen til et andet sted i abc2
-dataene lidt længere inde (ca. 50 MB) såvel som i starten. Den genererede “patch” var 4,6 MB stor, hvilket antyder, at kun de modificerede bits blev gemt i patchen.
Kommentarer
- Mange tak @Kusalananda, det ‘ er fantastisk! PS:
rsync --read-batch=abc-diff ${1:-abc}
(automatisk genereret .sh-script) gavremote destination is not allowed with --read-batch
rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2]
, menrsync --read-batch=abc-diff abc
fungerede med succes.Hvad er forskellen mellem disse to lignende kommandoer? - 2/2 Er der en måde at tage
abc
som input, anvende patchdiff-abc
med--read-batch
men ændrer ikkeabc
” på stedet “, men snarere output til en ny filabc3
? (hvis muligt alle medrsync
uden rør, så det fungerer let på Linux såvel som Windows, som også harrsync.exe
tilgængelig) - @Basj Kommandoerne ville gøre forskellige ting, hvis
$1
havde en værdi.${1:-abc}
betyder ” brug den første positionsparameter ($1
), medmindre den ‘ er tom eller udefineret. Hvis det ‘ er tomt eller udefineret, skal du brugeabc
i stedet for “. Jeg ‘ antager, at$1
havde en værdi, da du prøvede det, muligvis noget, det fortolkes som en ekstern destinationsadresse. - @Basj I ‘ Jeg er ikke helt sikker på, at dette er muligt, men jeg ‘ ll kig i morgen efter søvn.
- Tak for dit svar om
${1:-abc}
. Det mislykkedes sandsynligvis, fordi jeg prøvede det på Windows (jeg ‘ m ved hjælp af rsync både på Linux til min fjerne server og Windows lokalt). Men det er ‘ perfekt, darsync --read-batch=abc-diff abc
fungerer 🙂
Svar
Hvordan beregnes en binær diff af abc og abc2?
Brug af bsdiff / bspatch eller xdelta og andre.
$ bsdiff older newer patch.bin # patch.bin is created [...] $ bspatch older newer patch.bin # newer is created
Disse advarsler fra mandsiderne skal dog bemærkes:
-
bsdiff
bruger hukommelse svarende til 17 gange størrelsen på oldfile , og kræver en absolut minimumsstørrelse på arbejdssættet på 8 gange størrelsen på oldfile . -
bspatch
bruger hukommelse svarende til størrelsen på oldfile plus størrelsen på newfile , men tåler et meget lille arbejdssæt uden et dramatisk tab af ydeevne.
Kommentarer
Svar
Har du prøvet bare at tvinge diff
for at behandle filerne som tekst:
diff -ua abc abc2
Som forklaret her .
-
-u
output NUM (standard 3) linjer i en samlet kontekst -
-a
behandle alle filer som tekst
Dette skal give dig en patch. Ulempen ved dette er, at “linjerne” kan være ret lange, og det kan svulme plasteret op.
Kommentarer
- Ups, ja du don ‘ t vil faktisk have
n
. Jeg ‘ er interesseret i at vide, om det fungerer, da jeg ‘ er ikke sikker på, hvor længe ” linjer ” vil være. - Tak for din kommentar! Jeg oprettede to meget ens 256 MB filer
abc
ogabc2
. Så prøvede jegdiff -ua abc abc2 > patch
, så kopierede jegabc
tilabc3
og jeg forsøgte at komme migabc2
takket væreabc3
ogpatch
:patch abc3 < patch
, men det fungerede ikke: i slutningen varabc3
kun 1 KB i stedet for 256 MB. Har du nogen idé? - Hmmm, ved ikke hvad der skete. Jeg gjorde det bare på min maskine, og det fungerede bedre, end jeg havde forventet.Jeg tog en 382M-fil, der var tilfældige heltal skrevet ud i binær til en fil. Jeg ændrede 3 byte i det og gjorde diff og patch, og det fungerede. De resulterende filer var md5sum lige.
- Hvis en stor fil ikke har nogen byte
0x0a
, dvs. newline eller meget få, formoder jeg, at den ikke ville ‘ fungerer ikke så godt, det ville være interessant at teste. - Åh helt sikkert. Du kan lave et veluddannet gæt på en binær med
wc -l
som vil kigge efter linjeskift og efter min erfaring kører meget hurtigt. Jeg forventer på en vilkårlig binær, at det fungerer ret godt. For eksempel på min maskine fandt jeg en 252M mp4, der havde 1,2 millioner ” linjer “, og en 59M.deb
, der havde ca. 230k, så gennemsnit ” linjer ” på henholdsvis mindre end 220 bytes og 258 bytes. Jeg kan ikke ‘ ikke se, hvorfor disse filer ville være så forskellige end andre, men du kunne helt sikkert blive uheldig. I praksis formoder jeg, at det ville fungere ret godt, og hvis ikke, er det ‘ stadig et sjovt hack.
Svar
Brug xdelta , det blev oprettet nøjagtigt til denne type anvendelser. Baseret på VCDIFF (RFC 3284) i de nyeste versioner.
Kommentarer
- Linket fungerer ikke (er der en anden URL?). Kan du også tilføje et eksempel på nogle få linjer for at vise, hvordan du: 1) beregner diff
patch
-filen, og 2) gendannerabc2
, kun givetabc
ogpatch
? - Beklager, fast URL
- Tak @vonbrand . Vil du have et sådant eksempel?
Svar
Supplerer til andre svar i henhold til mine tests:
Med diff
oprettede jeg to meget ens 256 MB filer abc
og abc2
. Lad os derefter oprette diff-filen:
diff -ua abc abc2 > abc-abc2.diff
Lad os nu prøve at gendanne abc2
takket være original abc
fil og abc-abc2.diff
:
cp abc abc3 patch abc3 < abc-abc2.diff
eller
cp abc abc3 patch abc3 -i abc-abc2.diff
eller
patch abc -i abc-abc2.diff -o abc3
Det fungerer på Linux. Jeg prøvede også på Windows (patch.exe og diff.exe er også tilgængelige), men af en ukendt årsag mislykkedes det: den producerede abc3
-fil er kun 1 KB i stedet for 256 MB (I ” Opdater dette svar senere her).
Med rsync
Som beskrevet i det accepterede svar fungerer dette:
rsync --only-write-batch=abc-abc2-diff abc2 abc cp abc abc3 rsync --read-batch=abc-abc2-diff abc3
Med rdiff
Som beskrevet i dette svar , dette er også en løsning:
rdiff signature abc abc-signature rdiff delta abc-signature abc2 abc-abc2-delta rdiff patch abc abc-abc2-delta abc3
Testet også på Windows med rdiff.exe fra her og det fungerer.
Kommentarer
- Jeg ‘ jeg gætter på patch mislykkedes på Windows, fordi den læste inputfilen i ” tekst ” -tilstand, der signalerer slutningen af filen, når den støder på en KONTROL -Z (byte 0x18) i inputfilen. Dette er en ældre tilstand fra tidlige DOS-dage, hvor biblioteket ikke registrerede længden på filen, og så blev fillængden beregnet ud fra antallet af 512 byte sektorer. Hvis du kan fortælle
patch
at åbne filen i binær tilstand, skal den ikke ‘ ikke have denne fejl.
bsdiff uses memory equal to 17 times the size of oldfile
så dette vinder ‘ fungerer normalt ikke til 4 GB filer (i det mindste på min 8 GB RAM-maskine).mydiff abc abc2 > patchfile
ogmypatch abc patchfile > abc3
) uanset størrelse. Også, hvis jeg hugger i 128 MB stykker, hvad sker der hvis den første 1 GBabc
== den sidste (efterfølgende) 1 GBabc2
? Når vi ‘ sammenlignerabc-first128mb
medabc2-first128mb
, findes der ingen match, så det måske ikke effektiv?