【问题标题】:Binary patch-generation in C#C# 中的二进制补丁生成
【发布时间】:2010-09-05 13:42:26
【问题描述】:

是否有人拥有或知道 C# 中的二进制补丁生成算法实现?

基本上,比较两个文件(指定oldnew),并产生一个补丁文件,可以用来升级old文件具有与 new 文件相同的内容。

实现必须相对较快,并且可以处理大文件。它应该表现出 O(n) 或 O(logn) 运行时。

我自己的算法要么很糟糕(速度快但会产生巨大的补丁),要么很慢(产生小补丁但运行时间为 O(n^2))。

任何建议或实施指南都会很好。

具体来说,该实现将用于为我们拥有一台主服务器的各种大型数据文件保持服务器同步。当主服务器数据文件发生变化时,我们也需要更新几台异地服务器。

我做过的最天真的算法,只适用于可以保存在内存中的文件,如下:

  1. old 文件中获取前四个字节,称之为 key
  2. 将这些字节添加到字典中,其中 key -> position,其中 position 是我抓取这 4 个字节的位置,以 0 开头
  3. 跳过这四个字节中的第一个,抓取另外 4 个(3 个重叠,1 个),并以相同的方式添加到字典中
  4. old 文件中的所有 4 字节块重复步骤 1-3
  5. new 文件的开头,抓取 4 个字节,并尝试在字典中查找它
  6. 如果找到,则通过比较两个文件中的字节数找到最长的匹配项(如果有多个)
  7. old 文件中编码对该位置的引用,并在 new 文件中跳过匹配的块
  8. 如果没有找到,从 new 文件中编码 1 个字节,然后跳过它
  9. new 文件的其余部分重复步骤 5-8

这有点像压缩,没有窗口,所以会占用大量内存。但是,只要我尽量减少代码输出,它就相当快,并且会产生非常小的补丁。

一种更节省内存的算法使用窗口,但会产生更大的补丁文件。

我在这篇文章中跳过了上述算法的更多细微差别,但如有必要,我可以发布更多细节。然而,我确实觉得我需要一个完全不同的算法,所以改进上述算法可能还不够。


编辑#1:这里是对上述算法的更详细描述。

首先,合并两个文件,这样你就有了一个大文件。记住两个文件之间的切入点。

其次,为整个文件中的所有内容获取 4 个字节并将它们的位置添加到字典中步骤。

第三,从 new 文件开始的地方开始循环,尝试定位 4 个字节的现有组合,并找到最长的匹配项。确保我们只考虑旧文件中的位置,或新文件中比我们当前所处位置更早的位置。这确保了我们可以在补丁应用期间重用旧文件和新文件中的材料。


编辑#2Source code to the above algorithm

您可能会收到有关证书存在问题的警告。我不知道如何解决,所以暂时只接受证书。

源代码使用了我库的其余部分中的许多其他类型,因此该文件并不是它所需要的全部,但这就是算法实现。


@lomaxx,我试图为 subversion 中使用的算法找到一个很好的文档,称为 xdelta,但除非你已经知道该算法是如何工作的,否则我找到的文档无法告诉我我需要知道什么。

或者也许我只是很密集...... :)

我从您提供的那个站点快速浏览了算法,很遗憾它无法使用。来自二进制差异文件的评论说:

找到一组最佳差异需要相对于输入大小的二次时间,因此它很快就会变得不可用。

虽然我的需求不是最佳的,所以我正在寻找更实用的解决方案。

感谢您的回答,如果我需要的话,可以在他的实用程序中添加一个书签。

编辑#1:注意,我会查看他的代码,看看我是否能找到一些想法,稍后我还会向他发送一封包含问题的电子邮件,但我已经阅读了他参考的书,虽然该解决方案有助于找到最佳解决方案,但由于时间要求,它在使用中是不切实际的。

编辑#2:我一定会寻找 python xdelta 实现。

【问题讨论】:

标签: c# file patch


【解决方案1】:

抱歉,我无法提供更多帮助。我肯定会继续关注 xdelta,因为我已经多次使用它来生成我们为分发产品而生成的 600MB+ ISO 文件的质量差异,并且它的性能非常好。

【讨论】:

  • 是的,xdelta 很好。但是,它确实可以在相对较小的窗口上工作(如果我没记错的话,100kb),但是通过它的工作实现,我可以轻松地为我们的数据调整它。如果我没记错的话,选择窗口大小是为了提高颠覆的速度,但是我们的代码可以轻松运行更长的时间,只要它不需要花费一整夜(我当前的实现就是这样做的)。
【解决方案2】:

bsdiff 旨在为二进制文件创建非常小的补丁。如其页面所述,它需要max(17*n,9*n+m)+O(1) 字节的内存并在O((n+m) log n) 时间运行(其中n 是旧文件的大小,m 是新文件的大小)。

最初的实现是用 C 语言实现的,但是描述了一个 C# 端口 here 和可用的 here

【讨论】:

    【解决方案3】:

    你见过VCDiff吗?它是看起来相当活跃的 Misc 库的一部分(最新版本 r259,2008 年 4 月 23 日)。我没用过,但觉得值得一提。

    【讨论】:

      【解决方案4】:

      可能值得看看其他一些人在这个领域所做的事情,但也不一定是在 C# 领域。

      This is a library written in c#

      SVN 也有一个二进制差异算法,我知道在 python 中有一个实现,尽管我无法通过快速搜索找到它。他们可能会给你一些关于在哪里改进你自己的算法的想法

      【讨论】:

      • SVN 使用 xdelta 算法(至少从源码来看)
      【解决方案5】:

      如果这是用于安装或分发,您是否考虑过使用 Windows Installer SDK?它具有修补二进制文件的能力。

      http://msdn.microsoft.com/en-us/library/aa370578(VS.85).aspx

      【讨论】:

        【解决方案6】:

        这是一个粗略的指导,但以下是可用于创建二进制补丁的 rsync 算法。

        http://rsync.samba.org/tech_report/tech_report.html

        【讨论】:

          猜你喜欢
          • 2020-07-25
          • 2010-12-29
          • 1970-01-01
          • 1970-01-01
          • 2020-07-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多