【发布时间】:2010-09-05 13:42:26
【问题描述】:
是否有人拥有或知道 C# 中的二进制补丁生成算法实现?
基本上,比较两个文件(指定old和new),并产生一个补丁文件,可以用来升级old文件具有与 new 文件相同的内容。
实现必须相对较快,并且可以处理大文件。它应该表现出 O(n) 或 O(logn) 运行时。
我自己的算法要么很糟糕(速度快但会产生巨大的补丁),要么很慢(产生小补丁但运行时间为 O(n^2))。
任何建议或实施指南都会很好。
具体来说,该实现将用于为我们拥有一台主服务器的各种大型数据文件保持服务器同步。当主服务器数据文件发生变化时,我们也需要更新几台异地服务器。
我做过的最天真的算法,只适用于可以保存在内存中的文件,如下:
- 从 old 文件中获取前四个字节,称之为 key
- 将这些字节添加到字典中,其中 key -> position,其中 position 是我抓取这 4 个字节的位置,以 0 开头
- 跳过这四个字节中的第一个,抓取另外 4 个(3 个重叠,1 个),并以相同的方式添加到字典中
- 对 old 文件中的所有 4 字节块重复步骤 1-3
- 从 new 文件的开头,抓取 4 个字节,并尝试在字典中查找它
- 如果找到,则通过比较两个文件中的字节数找到最长的匹配项(如果有多个)
- 在 old 文件中编码对该位置的引用,并在 new 文件中跳过匹配的块
- 如果没有找到,从 new 文件中编码 1 个字节,然后跳过它
- 对 new 文件的其余部分重复步骤 5-8
这有点像压缩,没有窗口,所以会占用大量内存。但是,只要我尽量减少代码输出,它就相当快,并且会产生非常小的补丁。
一种更节省内存的算法使用窗口,但会产生更大的补丁文件。
我在这篇文章中跳过了上述算法的更多细微差别,但如有必要,我可以发布更多细节。然而,我确实觉得我需要一个完全不同的算法,所以改进上述算法可能还不够。
编辑#1:这里是对上述算法的更详细描述。
首先,合并两个文件,这样你就有了一个大文件。记住两个文件之间的切入点。
其次,为整个文件中的所有内容获取 4 个字节并将它们的位置添加到字典中步骤。
第三,从 new 文件开始的地方开始循环,尝试定位 4 个字节的现有组合,并找到最长的匹配项。确保我们只考虑旧文件中的位置,或新文件中比我们当前所处位置更早的位置。这确保了我们可以在补丁应用期间重用旧文件和新文件中的材料。
编辑#2:Source code to the above algorithm
您可能会收到有关证书存在问题的警告。我不知道如何解决,所以暂时只接受证书。
源代码使用了我库的其余部分中的许多其他类型,因此该文件并不是它所需要的全部,但这就是算法实现。
@lomaxx,我试图为 subversion 中使用的算法找到一个很好的文档,称为 xdelta,但除非你已经知道该算法是如何工作的,否则我找到的文档无法告诉我我需要知道什么。
或者也许我只是很密集...... :)
我从您提供的那个站点快速浏览了算法,很遗憾它无法使用。来自二进制差异文件的评论说:
找到一组最佳差异需要相对于输入大小的二次时间,因此它很快就会变得不可用。
虽然我的需求不是最佳的,所以我正在寻找更实用的解决方案。
感谢您的回答,如果我需要的话,可以在他的实用程序中添加一个书签。
编辑#1:注意,我会查看他的代码,看看我是否能找到一些想法,稍后我还会向他发送一封包含问题的电子邮件,但我已经阅读了他参考的书,虽然该解决方案有助于找到最佳解决方案,但由于时间要求,它在使用中是不切实际的。
编辑#2:我一定会寻找 python xdelta 实现。
【问题讨论】:
-
源代码链接失效。请问可以更新一下吗?
-
那段特定的代码已发布,这是我当前的版本,虽然我已经很久没有维护那个库了:lassevk.kilnhg.com/Code/LVK-for-NET/net-40/trunk/Files/…