在内存中保存大型可编辑文档的最佳方法

时间:2009-05-08 08:01:44

标签: c# algorithm data-structures string document

我需要在内存中保存文档的表示,并且正在寻找最有效的方法来执行此操作。

假设

  • 文件可能很大,很高 到100MB。
  • 通常是文件 将保持不变 - (即我没有 想要在前面做不必要的事情 处理)。
  • 变化通常非常接近 文件中的彼此(即 用户类型)。
  • 应该可以快速应用更改(不复制整个文档)
  • 将根据更改应用更改 偏移和新/删除的文本(不是 线/列)。
  • 使用C#

目前的考虑因素

  • 将数据存储为字符串。容易 代码,快速设置,非常慢 更新
  • 行数组,模式易于编码,设置较慢(因为我们必须将字符串解析为行),更新速度更快(因为我们可以轻松插入删除行,但查找偏移量需要求和行长度)。

对于这种事情,必须有大量的标准算法(这不是一百万英里的磁盘分配和碎片)。

感谢您的想法。

7 个答案:

答案 0 :(得分:4)

我建议将文件分成块。加载时,所有块都具有相同的长度,但如果用户编辑此块,则每个块的长度可能会更改。如果用户在前面插入一个字节,这可以避免移动100兆字节的数据。

要管理块,只需将它们与每个块的偏移量一起放入列表中。如果用户修改了块长度,则必须仅在此块之后更新块的偏移量。要查找偏移量,可以使用二分查找。

文件大小: 100 MiB
块大小: 16 kiB
阻止:6400

使用二分搜索查找偏移量(最差情况): 13步骤
修改块(最坏情况):复制16384字节数据并更新6400块偏移量 修改块(平均情况):复制8192字节数据并更新3200块偏移量

16 kiB块大小只是一个随机示例 - 您可以通过选择块大小来平衡操作的成本,可能基于文件大小和操作概率。做一些简单的数学运算会产生最佳的块大小。

加载速度非常快,因为你加载固定大小的块,保存也应该运行良好,因为你必须编写几千个块而不是数百万个单行。您可以通过仅按需加载块来优化加载,并且您可以通过仅保存更改的所有块(内容或偏移)来优化保存。

最后,实施也不会很难。您可以使用StringBuilder类来表示块。但是这种解决方案不适用于长度与块大小相当或更大的非常长的线路,因为您将需要加载许多块并仅显示一小部分,其余部分位于窗口的左侧或右侧。我假设在这种情况下你将不得不使用二维分区模型。

答案 1 :(得分:4)

Good Math,Bad Math在前一段时间写了一篇很好的article about ropes and gap buffer文章,详细介绍了在文本编辑器中表示文本文件的标准方法,甚至还比较了它们的简单实现和性能。简而言之:间隙缓冲区 - 一个大字符数组,在光标的当前位置之后立即有一个空部分 - 是最简单和最好的选择。

答案 2 :(得分:2)

你可能会发现这篇论文很有用--- Data Structures for Text Sequences描述和实验分析了一些标准算法,并比较了[等等]间隙缓冲区和片段表。

FWIW,它得出的结论表总体上略胜一筹;虽然net.wisdom似乎更喜欢间隙缓冲区。

答案 3 :(得分:1)

答案 4 :(得分:1)

如果您不打算编辑太多,我会使用b-tree或跳过行列表或更大的块。

您在加载时没有太多额外费用确定行结束,因为您必须在加载时访问每个字符。

您可以毫不费力地在节点内移动线条。

每个节点中文本的总长度存储在节点中,并且更改传播到父节点。

每一行由数据数组表示,并且起始索引,长度和容量。换行符/回车符不放在数据数组中。诸如断行之类的常见操作仅需要更改对数组的引用;如果超出容量,编辑行需要副本。编辑该行时,每行可能会暂时使用类似的结构,因此您不会在每次按键时执行复制。

答案 5 :(得分:0)

除了你有一些非常长行之外,我认为索引链表对于这类事情会相当有效。

链接列表将为您提供一种有效的方式来存储数据,并在用户编辑时添加或删除行。索引允许您快速跳转到文件中的特定点。这种想法很适合撤消/重做类型操作,因为将编辑分类为小型原子操作应该相当容易。

我同意明确的观点,但最好先让一些简单的工作,然后看看它真的 慢......

答案 6 :(得分:-1)

从你的描述中听起来很像你的文档只是未格式化的文本 - 所以一个字符串构建器就可以了。

如果它是一个格式化的文档,我会倾向于使用MS Word API或者类似的东西,只是将文档处理卸载到它们 - 这将节省您大量的时间,因为文档解析通常会让a *感到痛苦*: - )

我不会太担心性能 - 听起来很像你还没有实现它,所以你也不知道应用程序其余部分的性能特征 - 可能是你实际上,当你真正进行分析时,实际上根本无法在内存中保存多个文档。