5

我需要在内存中保存一个文档的表示,并且正在寻找最有效的方法来做到这一点。

假设

  • 文档可能非常大,最大为 100MB。
  • 文档通常会保持不变——(即我不想做不必要的前期处理)。
  • 文档中的更改通常会非常接近(即,当用户键入时)。
  • 应该可以快速应用更改(无需复制整个文档)
  • 将根据偏移量和新/删除的文本(而不是行/列)应用更改。
  • 在 C# 中工作

目前的考虑

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

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

谢谢你的想法。

4

7 回答 7

5

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

要管理这些块,只需将它们 - 连同每个块的偏移量 - 放入一个列表中。如果用户修改了一个块的长度,你必须只更新这个块之后的偏移量。要查找偏移量,您可以使用二进制搜索。

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

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

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

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

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

于 2009-05-08T08:26:29.383 回答
4

Good Math, Bad Math 不久前写了一篇关于绳索和间隙缓冲区的优秀文章,详细介绍了在文本编辑器中表示文本文件的标准方法,甚至为了实现的简单性和性能进行了比较。简而言之:间隙缓冲区 - 一个大字符数组,在光标当前位置之后有一个空白部分 - 是您最简单和最好的选择。

于 2009-05-08T10:10:46.357 回答
3

您可能会发现这篇论文很有用——文本序列的数据结构,它描述并通过实验分析了一些标准算法,并比较了 [除其他外] 间隙缓冲区和片段表。

FWIW,它得出的结论是整体表略好一些;虽然 net.wisdom 似乎更喜欢间隙缓冲区。

于 2009-07-21T16:37:27.917 回答
1

我建议您看一下内存映射文件(MMF)。

一些指示:

内存映射文件 .NET

http://msdn.microsoft.com/en-us/library/ms810613.aspx

于 2009-05-08T08:08:30.550 回答
1

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

您没有太多额外的成本来确定加载时的行尾,因为无论如何您都必须在加载时访问每个字符。

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

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

每行由一个数据数组表示,以及起始索引、长度和容量。换行符/回车符不放在数据数组中。断线等常用操作只需要修改对数组的引用即可;如果超出容量,编辑行需要副本。编辑该行时,每行可能会临时使用类似的结构,因此您不必在每次按键时都执行复制。

于 2009-05-08T09:41:39.873 回答
0

在我的脑海中,我会认为索引链表对于这类事情会相当有效,除非你有一些长的行。

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

不过,我同意 crisb 的观点,最好先让一些简单的工作,然后看看它是否真的慢。

于 2009-05-08T08:16:37.957 回答
-1

从您的描述中,听起来很像您的文档只是未格式化的文本-因此字符串生成器就可以了。

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

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

于 2009-05-08T08:13:10.367 回答