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