假设abc
我的本地计算机上有一个 4 GB 的文件。我已经通过SFTP将其上传到远程服务器,花了几个小时。
现在我在本地稍微修改了该文件(最大可能为 50 MB,但该文件中不是连续的字节),并将其保存到abc2
.我还将原始文件保留abc
在本地计算机上。
如何计算abc
和的二进制差异abc2
?
应用:
我只能将一个
patch
文件(可能最大 100MB)发送到远程服务器,而不是重新上传整个abc2
文件(又需要几个小时!),并仅abc2
在远程服务器上重新创建。abc
patch
在本地,我可以只保存+ ,而不是浪费 8 GB 来备份
abc
和,因此只需 < 4100 MB。abc2
abc
patch
这个怎么做?
PS:对于文本,我知道diff
,但在这里我正在寻找可以适用于任何原始二进制格式的东西,它可以是 zip 文件或可执行文件,甚至其他类型的文件。
PS2:如果可以的话,我不想用rsync
;我知道它可以以有效的方式在两台计算机之间复制更改(不重新发送未更改的数据),但在这里我真的想要一个文件,如果我同时拥有和 ,则patch
稍后可以复制该文件。abc
patch
答案1
restic
对于第二个应用程序/问题,我将使用类似或 的重复数据删除备份程序borgbackup
,而不是尝试手动跟踪“补丁”或差异。该restic
备份程序允许您将多台计算机上的目录备份到同一备份存储库,从而在单个计算机上以及计算机之间的文件片段之间消除重复的备份数据。 (我没有使用 的用户经验borgbackup
,所以我不能对这个程序说任何话。)
可以使用 来计算和存储abc
和文件的差异。abc2
rsync
这是一个大小为abc
153 abc2
MB 的示例。该文件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 文件abc
和abc2
.然后让我们创建 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 进行了测试这里它有效。