4GBのファイルabc
があるとします。ローカルコンピュータ。SFTP経由で離れたサーバーにアップロードしました。数時間かかりました。
ファイルを少し変更しました(おそらく最大50 MBですが、このファイルの連続バイトではありません)。 abc2
に保存しました。元のファイルabc
もローカルコンピューターに保存しました。
abc
とabc2
のバイナリ差分を計算する方法は?
アプリケーション:
-
patch
ファイル(おそらく最大100MB)をに送信することしかできませんでしたabc2
ファイル全体を再アップロードする代わりに(再び数時間かかります!)、離れたサーバーでabc2
を再作成します。abc
およびpatch
からのサーバーのみ。 -
ローカルでは、
abc
とabc2
の両方をバックアップするために8GBを浪費する代わりに、保存できるのはabc
+patch
なので、< 4100MBのみかかります。
これを行う方法は?
PS:テキストの場合、diff
を知っていますが、ここで探しています生のバイナリ形式で機能するもので、zipファイルや実行可能ファイル、その他の種類のファイルでもかまいません。
PS2:可能であれば、; 2台のコンピューター間で変更を効率的に複製できることはわかっていますが(変更されていないデータを再送信することはありません)、ここでpatch
ファイルを作成します。これは後で再現できます。 abc
とpatch
の両方があります。
回答
2番目のアプリケーション/問題では、試してみるのではなく、restic
やborgbackup
のような重複排除バックアッププログラムを使用します「パッチ」または差分を手動で追跡します。 restic
バックアッププログラムを使用すると、複数のマシンから同じバックアップリポジトリにディレクトリをバックアップし、個々のマシンのファイルフラグメント間およびマシン間でバックアップデータを重複排除できます。 (borgbackup
のユーザーエクスペリエンスがないため、そのプログラムについては何も言えません。)
abc
およびabc2
ファイルはrsync
で実行できます。
これは例ですabc
とabc2
は153MBです。ファイルabc2
は、ファイルの最初の2.3MBとその他のデータ:
$ 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
作成しますabc
をabc2
に変換し、それを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
生成されたファイルabc-diff
は実際の差分(「パッチファイル」)ですが、abc-diff.sh
はrsync
が作成する短いシェルスクリプト:
$ cat abc-diff.sh rsync --read-batch=abc-diff ${1:-abc}
このスクリプトは、ファイルiv id = “f91b090ab2を指定すると、abc
がabc2
と同じになるように変更します。 “>
:
$ md5sum abc abc2 be00efe0a7a7d3b793e70e466cbc53c6 abc 3decbde2d3a87f3d954ccee9d60f249b abc2 $ sh abc-diff.sh $ md5sum abc abc2 3decbde2d3a87f3d954ccee9d60f249b abc 3decbde2d3a87f3d954ccee9d60f249b abc2
ファイルabc-diff
は、abc
がある他の場所に転送できるようになりました。コマンドrsync --read-batch=abc-diff abc
を使用して、パッチをファイルabc
に適用し、その内容をabc2
ファイル。
パッチをもう一度再適用するのは安全だと思われます。エラーメッセージもファイルの内容も変更されません(MD5チェックサムは変更されません)。
明示的な「リバースパッチ」を作成しない限り、アプリケーションを簡単に元に戻す方法はないことに注意してください。パッチの。
abc2
データの別の場所(約50)に2.3MBの変更を書き込むこともテストしました。 MB)、および開始時。生成された「パッチ」は4.6 MBの大きさであり、変更されたビットのみがパッチに格納されたことを示しています。
コメント
回答
abcとabc2のバイナリ差分を計算する方法
bsdiff / bspatch またはxdeltaなどを使用します。
$ bsdiff older newer patch.bin # patch.bin is created [...] $ bspatch older newer patch.bin # newer is created
ただし、manページからのこれらの警告には注意が必要です。
-
bsdiff
は、の17倍のサイズのメモリを使用します。 oldfile であり、 oldfile のサイズの8倍の絶対最小ワーキングセットサイズが必要です。 -
bspatch
は、 oldfile のサイズに newfile のサイズを加えたものに等しいメモリを使用しますが、パフォーマンスを大幅に低下させることなく、非常に小さなワーキングセットに耐えることができます。
コメント
- 例を示していただけませんか?
- 回答ありがとうございます。
bsdiff uses memory equal to 17 times the size of oldfile
なので、これは通常4GBファイルでは機能しません(少なくとも私の8GB RAMマシンでは)。 - @Basj可能なことは、4GBのファイルをより小さなファイル(たとえば、それぞれ128MB)に切り刻み、個々のデルタを実行することです。これはスクリプトにラップすることができます。 chopped-bsdiff:ファイルを切り刻み、ペアワイズbsdiffを実行し、それらをアーカイブにtarします。 chopped-bspatch:アーカイブからペアワイズパッチを読み取り、入力ファイルのチャンクに適用し、出力を連結します。
- @Kazなるほどですが、’もっと探していますサイズに関係なく、1行で呼び出すことができるすぐに使用できるツール(
mydiff abc abc2 > patchfile
およびmypatch abc patchfile > abc3
)。また、128 MBのチャンクに切り刻んだ場合、abc
の最初の1GB ==abc2
の最後の(末尾の)1GBの場合はどうなりますか? ‘をabc-first128mb
とabc2-first128mb
と比較すると、一致するものが見つからないため、効率的ではない可能性がありますか?
回答
diff
ファイルをテキストとして処理するには:
diff -ua abc abc2
説明どおりここ。
-
-u
統合コンテキストのNUM(デフォルトは3)行を出力 -
-a
すべてのファイルをテキストとして扱います
これでパッチが適用されます。これの欠点は、「線」が非常に長くなり、パッチが肥大化する可能性があることです。
コメント
- おっと、そうですね’実際には
n
が必要です。 ‘それがI ‘として機能するかどうか知りたいのですが、” lines “になります。 - コメントありがとうございます! 2つの非常によく似た256MBファイル
abc
とabc2
を作成しました。次に、diff -ua abc abc2 > patch
を試し、次にabc
をabc3
にコピーして、回復しようとしましたdiff -ua abc abc2 > patch
div id = “969241e5c0”>
abc3
とpatch
のおかげで:patch abc3 < patch
、しかしそれは機能しませんでした:最後にabc3
は256MBではなく1KBでした。何か考えはありますか?
0x0a
、つまり改行、または非常に少ない場合は、うまく機能しないので、テストするのは面白いでしょう。wc -l
を使用すると、バイナリについて知識に基づいた推測を行うことができます。これにより、改行が検索され、私の経験では非常に高速に実行されます。私は、任意のバイナリでそれがかなりうまくいくと期待します。たとえば、私のマシンでは、120万の”行”と59Mのは約230kだったので、平均”行”はそれぞれ220バイトと258バイト未満でした。 ‘これらのファイルが他のファイルとそれほど異なる理由はわかりませんが、間違いなく不運になる可能性があります。実際には、それはかなりうまくいくと思いますが、そうでない場合でも’はまだ楽しいハックです。回答
xdelta を使用します。これは、まさにこのタイプの用途のために作成されました。最新バージョンのVCDIFF(RFC 3284)に基づいています。
コメント
- リンクが機能していません(別のURLはありますか?)。また、数行に例を追加して、次の方法を示すこともできます。1)diff
patch
ファイルを計算し、2)abc2
を復元する、abc
とpatch
のみを指定しますか? - 申し訳ありませんが、固定URL
- @vonbrandに感謝します。そのような例はありますか?
回答
私のテストによる他の回答の補足:
diff
2つの非常によく似た256MBファイルabc
と。次に、diffファイルを作成しましょう。
diff -ua abc abc2 > abc-abc2.diff
では、abc2
の復元を試みましょう。元のabc
ファイルとabc-abc2.diff
:
cp abc abc3 patch abc3 < abc-abc2.diff
または
cp abc abc3 patch abc3 -i abc-abc2.diff
または
patch abc -i abc-abc2.diff -o abc3
Linuxで動作します。 Windowsでも試しましたが(patch.exeとdiff.exeも利用可能です)、不明な理由で失敗しました。生成されたabc3
ファイルは256MBではなく1KBです(I “この回答は後でここで更新します。
rsync
承認された回答で詳しく説明されているように、これは機能します。
rsync --only-write-batch=abc-abc2-diff abc2 abc cp abc abc3 rsync --read-batch=abc-abc2-diff abc3
rdiff
の詳細回答、これも解決策です:
rdiff signature abc abc-signature rdiff delta abc-signature abc2 abc-abc2-delta rdiff patch abc abc-abc2-delta abc3
ここで機能します。
コメント
- 私は’だと思いますWindowsでパッチが失敗したのは、入力ファイルを” text “モードで読み取っていたため、CONTROLに遭遇したときにファイルの終わりを通知するためです。 -入力ファイルのZ(バイト0x18)。これは、ディレクトリが次の長さを記録しなかったDOS初期のレガシーモードです。ファイルであるため、ファイルの長さは512バイトのセクター数に基づいて計算されました。
patch
にファイルをバイナリモードで開くように指示できる場合、’このエラーは発生しないはずです。
rsync --read-batch=abc-diff ${1:-abc}
(自動生成された.shスクリプト)はremote destination is not allowed with --read-batch
rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2]
ですが、rsync --read-batch=abc-diff abc
は正常に機能しました。これら2つの類似したコマンドの違いは何ですか?abc
を入力として受け取り、パッチと--read-batch
を使用しますが、abc
“をインプレースで変更しません”ではなく、新しいファイルabc3
に出力しますか? (可能であれば、すべてrsync
を使用し、配管なしで、Linuxおよびrsync.exe
も利用可能なWindowsで簡単に動作するようにします)$1
に値がある場合、コマンドは異なることを行います。${1:-abc}
は、”最初の位置パラメータ($1
)を’が空または未定義です。 ‘が空または未定義の場合は、代わりにabc
を使用してください”。 ‘$1
を試したときに値があったと想定していますが、おそらくそれはリモートの宛先アドレス。${1:-abc}
についてお答えいただきありがとうございます。おそらく失敗したのは、Windowsで試したためです(私は’ mは、離れたサーバー用のLinuxとローカルのWindowsの両方でrsyncを使用しています)。ただし、’は、rsync --read-batch=abc-diff abc
が機能するため、完璧です:)