两个相似的大原始二进制文件的差异

两个相似的大原始二进制文件的差异

假设abc我的本地计算机上有一个 4 GB 的文件。我已经通过SFTP将其上传到远程服务器,花了几个小时。

现在我在本地稍微修改了该文件(最大可能为 50 MB,但该文件中不是连续的字节),并将其保存到abc2.我还将原始文件保留abc在本地计算机上。

如何计算abc和的二进制差异abc2

应用:

  • 我只能将一个patch文件(可能最大 100MB)发送到远程服务器,而不是重新上传整个abc2文件(又需要几个小时!),并仅abc2在远程服务器上重新创建。abcpatch

  • 在本地,我可以只保存+ ,而不是浪费 8 GB 来备份abc和,因此只需 < 4100 MB。abc2abcpatch

这个怎么做?

PS:对于文本,我知道diff,但在这里我正在寻找可以适用于任何原始二进制格式的东西,它可以是 zip 文件或可执行文件,甚至其他类型的文件。

PS2:如果可以的话,我不想用rsync;我知道它可以以有效的方式在两台计算机之间复制更改(不重新发送未更改的数据),但在这里我真的想要一个文件,如果我同时拥有和 ,则patch稍后可以复制该文件。abcpatch

答案1

restic对于第二个应用程序/问题,我将使用类似或 的重复数据删除备份程序borgbackup,而不是尝试手动跟踪“补丁”或差异。该restic备份程序允许您将多台计算机上的目录备份到同一备份存储库,从而在单个计算机上以及计算机之间的文件片段之间消除重复的备份数据。 (我没有使用 的用户经验borgbackup,所以我不能对这个程序说任何话。)

可以使用 来计算和存储abc和文件的差异。abc2rsync

这是一个大小为abc153 abc2MB 的示例。该文件abc2已被修改,用一些其他数据覆盖文件的前 2.3 MB:

$ 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是实际的 diff(您的“补丁文件”),同时是为您创建的abc-diff.sh一个简短的 shell 脚本:rsync

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

该脚本经过修改abc,使其与abc2给定文件的相同abc-diff

$ 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 校验和没有更改)。

请注意,除非您创建显式的“反向补丁”,否则无法轻松撤消补丁的应用。


我还测试了将 2.3 MB 的修改写入数据中的其他位置abc2,稍远一点(大约 50 MB),以及在开始处。生成的“补丁”大小为 4.6 MB,这表明只有修改后的位存储在补丁中。

答案2

如何计算 abc 和 abc2 的二进制差异?

使用bsdiff/bspatch或 xdelta 等。

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

然而,需要注意手册页中的这些警告:

  • bsdiff使用的内存等于大小的 17 倍旧文件,并且需要绝对最小工作集大小为 8 倍的大小旧文件
  • bspatch使用的内存大小等于旧文件加上大小新文件,但可以容忍非常小的工作集,而不会造成性能的显着损失。

答案3

您是否尝试过强制diff将文件视为文本:

diff -ua abc abc2

正如所解释的这里

  • -u输出 NUM(默认 3)行统一上下文
  • -a将所有文件视为文本

这应该会给你一个补丁。这样做的缺点是“行”可能会很长并且可能会使补丁变得臃肿。

答案4

根据我的测试对其他答案的补充:

diff

我创建了两个非常相似的 256 MB 文件abcabc2.然后让我们创建 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文件只有 1KB 而不是 256MB(我稍后会在这里更新这个答案)。

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 上使用 rdiff.exe 进行了测试这里它有效。

相关内容