【问题标题】:How to represent a random-access text file in memory (C)如何在内存中表示随机访问文本文件(C)
【发布时间】:2011-09-02 10:08:07
【问题描述】:

我正在做一个项目,我需要读取内存中的文本(源)文件并能够执行随机访问(例如,检索与第 3 行第 15 列对应的地址)。

我想知道是否有既定的方法可以做到这一点,或者数据结构特别适合这项工作。我需要能够执行(可能摊销)恒定时间访问。我正在使用 C 语言工作,但如果值得的话,我愿意实现更高级别的数据结构。

我的第一个想法是使用一个包含文件字符数据的大缓冲区链表。我还会创建一个数组,其索引是行号,内容是对应于行首的地址。该数组将根据需要重新分配。

辅助问题:有人知道源文件的平均大小吗?我很惊讶没有在谷歌上找到这个。

澄清一下:

我关心的文件是源文件,所以它们的大小应该是可管理的,它们不应该被修改,并且行的长度是可变的(希望限制在某个最大值)。

我正在处理的问题主要需要一个只读文件表示,但我对挖掘这个问题非常感兴趣。

结论:

Data Structures for Text Sequences 论文中对用于维护文件(支持读取/插入/删除)的数据结构进行了非常有趣的讨论。

如果您只需要只读,只需获取文件大小,使用 fread() 将其读取到内存中,然后您必须维护一个动态数组,该数组将行号(索引)映射到指向第一个字符的指针线。下面有人建议懒惰地构建这个数组,这在很多情况下似乎是个好主意。

【问题讨论】:

    标签: c file memory data-structures


    【解决方案1】:

    我不太确定这里的问题是什么,但似乎有点“我如何将文件保存在内存中”和“我如何索引它”。由于您需要随机访问文件的内容,因此建议您对文件进行内存映射,除非地址空间紧张。

    我认为您无法避免一次线性遍历文件以查找行尾。正如您所说,您可以创建指向每行开头的指针的索引。如果您不确定需要多少索引,请延迟创建(按需)。如果您在后续运行中需要它,您还可以将此索引存储到磁盘(作为偏移量,而不是指针)。您可以根据文件大小和预期的行长来估计索引的大小。

    【讨论】:

      【解决方案2】:

      1) 将整个文件读取(或映射)到一块内存中。

      2) 在第二遍中,创建一个指针或偏移数组,指向该内存中的行的开头(提示:在 '\n' 之后的一个)。

      现在您可以索引数组以访问特定行。

      【讨论】:

      • 注意:这种机制在台式 PC 上的索引速度约为 50MB/s,基本上是磁盘带宽。
      • 是的,用于只读(或不经常修改)数据结构。而且文件必须非常小才能完全放入内存。
      • 我从未见过 100MB 的源文件。在这种情况下, mmap() (如果可用)可以解决问题。下一步将是缓冲,扫描缓冲区中的“\n”,冲洗,重复。
      • 没人提到源代码,有很多东西的源文件,像图片源,地图源,...
      • 再一次,没有人提到源代码代码。再次阅读我的评论。
      【解决方案3】:

      在特定的行/列/字符地址同时进行插入、删除和读取是不可能的 O(1)。对于所有这些操作,您可以获得的最佳结果是同时 O(log n),并且可以使用各种平衡二叉树将文件存储在内存中来实现。

      当然,除非您的文件大于 100 kB 左右,否则您最好不要打扰任何花哨的东西,而只使用平坦的线性缓冲区...

      【讨论】:

        【解决方案4】:
        1. 解决方案:如果行的大小大致相同,则通过在每行附加所需数量的元字符来使所有行的长度相等。然后您可以简单地从行号计算 fseek() 位置,使您的搜索 O(1)。
        2. 如果行已排序,则您可以执行二分搜索,使您的搜索 O(log(nõLines))。
        3. 如果两者都没有,您可以存储行开头的索引。但是,如果您大量修改文件,您就会遇到问题,因为如果您在某处插入假设 X 字符,您必须计算它是哪一行,然后将此 X 添加到所有下一行。与删除类似。 Yu 基本上得到 O(nõLines)。并且代码变得丑陋

        如果要将整个文件存储在内存中,只需创建一行 *char[]。然后,您通过第一次取消引用和第二次取消引用获得字符。

        【讨论】:

          【解决方案5】:

          作为替代建议(尽管我不完全理解这个问题),您可能需要考虑一个基于结构的、动态链接的动态字符串列表。如果您想变得聪明,可以构建一个动态链接的字符列表,然后将其导出为字符串。

          您必须使用 OO 类型设计才能使其易于管理。

          所以你可能想要构建的结构是:

          动态数组;

          DynamicListOfArrays;

          字符列表;

          原来如此:

          CharList(获取字符/大小) -> (SetSize)DynamicArray -> (AddArray)DynamicListOfArrays

          如果您为 malloc 和 delete 构建合适的辅助函数,并使其结构可以自动或手动删除自己。使用上述组合不会让你 O(1) 读入(如果文件没有静态格式,这是不可能的),但它会让你玩得开心。

          如果您知道文件的静态长度(至少单行),IE 每行不超过 256 个字符,那么您只需要 DynamicListOfArries - 直接写入数组(预设为 256),创建一个新的, 重复。缺点是浪费内存。

          注意:您必须先将 DynamicListOfArrays 转换为“静态”ArrayOfArrays,然后才能获得直接点对点访问。

          如果您需要源代码来给您一个想法(虽然我的代码是针对 C++ 构建的,但不会花很长时间重写),请留下评论。与我在 stackoverflow 上提供的任何其他代码一样,它可以用于任何目的,甚至可以用于商业用途。

          【讨论】:

            【解决方案6】:

            源文件的平均大小?这样的事情存在吗?一个源文件可以从 0 字节到数千字节,就像任何文本文件一样,它取决于它包含的字符数

            【讨论】:

            • 根据程序员在现实世界中的实际使用,源文件的平均文件大小是多少?这是一个统计数据,很像人类当前的平均年龄。
            • 嗯,这就是我所说的,关于生产环境,例如,您有一些源文件只包含几百行,而其他可能包含数千行
            • 更具体的例子可以查看linuxsource code
            • 想象一下,您可以访问世界上所有由人类直接编辑的源代码文件。我寻求的是对该语料库中平均文件大小的估计。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-01-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-09-27
            相关资源
            最近更新 更多