2つの類似した大きな生のバイナリファイルの差分

4GBのファイルabcがあるとします。ローカルコンピュータ。SFTP経由で離れたサーバーにアップロードしました。数時間かかりました。

ファイルを少し変更しました(おそらく最大50 MBですが、このファイルの連続バイトではありません)。 abc2に保存しました。元のファイルabcもローカルコンピューターに保存しました。

abcabc2のバイナリ差分を計算する方法は?

アプリケーション:

  • patchファイル(おそらく最大100MB)をに送信することしかできませんでしたabc2ファイル全体を再アップロードする代わりに(再び数時間かかります!)、離れたサーバーでabc2を再作成します。 abcおよびpatchからのサーバーのみ。

  • ローカルでは、abcabc2の両方をバックアップするために8GBを浪費する代わりに、保存できるのはabc + patchなので、< 4100MBのみかかります。

これを行う方法は?

PS:テキストの場合、diffを知っていますが、ここで探しています生のバイナリ形式で機能するもので、zipファイルや実行可能ファイル、その他の種類のファイルでもかまいません。

PS2:可能であれば、; 2台のコンピューター間で変更を効率的に複製できることはわかっていますが(変更されていないデータを再送信することはありません)、ここでpatchファイルを作成します。これは後で再現できます。 abcpatchの両方があります。

回答

2番目のアプリケーション/問題では、試してみるのではなく、resticborgbackupのような重複排除バックアッププログラムを使用します「パッチ」または差分を手動で追跡します。 resticバックアッププログラムを使用すると、複数のマシンから同じバックアップリポジトリにディレクトリをバックアップし、個々のマシンのファイルフラグメント間およびマシン間でバックアップデータを重複排除できます。 (borgbackupのユーザーエクスペリエンスがないため、そのプログラムについては何も言えません。)

abcおよびabc2ファイルはrsyncで実行できます。

これは例ですabcabc2は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  

作成しますabcabc2に変換し、それを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.shrsyncが作成する短いシェルスクリプト:

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

このスクリプトは、ファイルiv id = “f91b090ab2を指定すると、abcabc2と同じになるように変更します。 “>

 $ 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の大きさであり、変更されたビットのみがパッチに格納されたことを示しています。

コメント

  • @Kusalanandaに感謝します、’すばらしいです!PS: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つの類似したコマンドの違いは何ですか?
  • 2/2 abcを入力として受け取り、パッチと--read-batchを使用しますが、abc “をインプレースで変更しません”ではなく、新しいファイルabc3に出力しますか? (可能であれば、すべてrsyncを使用し、配管なしで、Linuxおよびrsync.exeも利用可能なWindowsで簡単に動作するようにします)
  • @Basj $1に値がある場合、コマンドは異なることを行います。 ${1:-abc}は、”最初の位置パラメータ($1)を’が空または未定義です。 ‘が空または未定義の場合は、代わりにabcを使用してください”。 ‘ $1 を試したときに値があったと想定していますが、おそらくそれはリモートの宛先アドレス。
  • @Basj I ‘これが可能かどうかは完全にはわかりませんが、’ ll明日は寝てから見てください。
  • ${1:-abc}についてお答えいただきありがとうございます。おそらく失敗したのは、Windowsで試したためです(私は’ mは、離れたサーバー用のLinuxとローカルのWindowsの両方でrsyncを使用しています)。ただし、’は、rsync --read-batch=abc-diff abcが機能するため、完璧です:)

回答

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-first128mbabc2-first128mbと比較すると、一致するものが見つからないため、効率的ではない可能性がありますか?

回答

diffファイルをテキストとして処理するには:

diff -ua abc abc2 

説明どおりここ

  • -u統合コンテキストのNUM(デフォルトは3)行を出力
  • -aすべてのファイルをテキストとして扱います

これでパッチが適用されます。これの欠点は、「線」が非常に長くなり、パッチが肥大化する可能性があることです。

コメント

  • おっと、そうですね’実際にはnが必要です。 ‘それがI ‘として機能するかどうか知りたいのですが、” lines “になります。
  • コメントありがとうございます! 2つの非常によく似た256MBファイルabcabc2を作成しました。次に、diff -ua abc abc2 > patchを試し、次にabcabc3にコピーして、回復しようとしましたdiff -ua abc abc2 > patch div id = “969241e5c0”>

abc3patchのおかげで:patch abc3 < patch、しかしそれは機能しませんでした:最後にabc3は256MBではなく1KBでした。何か考えはありますか?

  • うーん、何が起こったのかわかりません。私は自分のマシンでそれを実行しましたが、予想よりもうまく機能しました。ランダムな整数がバイナリでファイルに書き出された382Mのファイルを取りました。その中で3バイトを変更し、diffとpatchを実行すると、機能しました。結果のファイルはmd5sumと同等でした。
  • 大きなファイルにバイトがない場合0x0a、つまり改行、または非常に少ない場合は、うまく機能しないので、テストするのは面白いでしょう。
  • 確かに。 wc -lを使用すると、バイナリについて知識に基づいた推測を行うことができます。これにより、改行が検索され、私の経験では非常に高速に実行されます。私は、任意のバイナリでそれがかなりうまくいくと期待します。たとえば、私のマシンでは、120万の”行”と59Mのは約230kだったので、平均”行”はそれぞれ220バイトと258バイト未満でした。 ‘これらのファイルが他のファイルとそれほど異なる理由はわかりませんが、間違いなく不運になる可能性があります。実際には、それはかなりうまくいくと思いますが、そうでない場合でも’はまだ楽しいハックです。
  • 回答

    xdelta を使用します。これは、まさにこのタイプの用途のために作成されました。最新バージョンのVCDIFF(RFC 3284)に基づいています。

    コメント

    • リンクが機能していません(別のURLはありますか?)。また、数行に例を追加して、次の方法を示すこともできます。1)diff patchファイルを計算し、2)abc2を復元する、abcpatchのみを指定しますか?
    • 申し訳ありませんが、固定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にファイルをバイナリモードで開くように指示できる場合、’このエラーは発生しないはずです。

    コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です