代码之家  ›  专栏  ›  技术社区  ›  Andreas Bonini

写入文件中间(不覆盖数据)

  •  8
  • Andreas Bonini  · 技术社区  · 15 年前

    在Windows中,是否可以通过API将文件写到文件中间而不覆盖任何数据,也不必在文件中间重写所有内容?

    如果可能的话,那么我相信它会很明显地将文件分割开来;在它成为一个严重问题之前,我可以做多少次?

    如果不可能,通常采取什么方法/解决方法?在插入点之后重新编写所有内容,对于大文件(即,千兆字节)来说非常快就变得令人望而却步。


    注意 :我不得不写到中间。把这个应用程序想象成一个文本编辑器,可以编辑用户键入内容然后保存的巨大文件。我也不能将文件拆分成几个较小的文件。

    6 回复  |  直到 12 年前
        1
  •  8
  •   paxdiablo    15 年前

    我不知道怎么做 如果您需要的临时结果是一个平面文件,可以由编辑器以外的其他应用程序使用 . 如果您希望生成一个平面文件,则必须将其从更改点更新到文件末尾,因为它实际上只是一个连续文件。

    但是斜体字的出现是有原因的。如果您可以控制文件格式,那么您有一些选项。有些版本的MS Word具有快速保存功能,在该功能中,他们没有重写整个文档,而是在文件末尾附加了一个增量记录。然后,在重新读取文件时,它按顺序应用了所有增量,这样最终得到的就是正确的文件。如果保存的文件必须立即可用于另一个不理解文件格式的应用程序,这显然不会起作用。

    我的建议是 将文件存储为文本。使用一个可以有效地编辑和保存的中间表单,然后使用一个步骤将其转换为不经常使用的文本文件(例如,在编辑器退出时)。这样,用户可以节省他们想要的,但昂贵的操作时间不会有太大的影响。

    除此之外,还有其他一些可能性。

    内存映射(而不是加载)文件 可以 提高效率,加快速度。您可能仍然需要重写到文件的末尾,但这将在操作系统的较低级别上发生。

    如果希望快速保存的主要原因是开始让用户继续工作(而不是让其他应用程序可以使用该文件),则可以将保存操作转移到单独的线程,并立即将控件返回给用户。然后,您需要在两个线程之间进行同步,以防止用户修改尚未保存到磁盘上的数据。

        2
  •  4
  •   Jerry Coffin    15 年前

    现实的答案是否定的。您唯一真正的选择是从修改的角度重写,或者构建一种更复杂的格式,它使用索引之类的东西来告诉如何将记录排列成预期的顺序。

    从纯理论的观点来看,你 能够 在适当的环境下做。使用FAT(例如,但大多数其他文件系统至少具有某种程度的相似性),您可以进入并直接操纵FAT。FAT基本上是组成文件的集群的链接列表。您可以修改该链接列表,在文件中间添加一个新集群,然后将新数据写入您添加的集群。

    请注意,我说的纯粹是理论上的。在像MS-DOS这样一个完全不受保护的系统下进行这种操作是困难的,但接近于合理的。对于大多数更新的系统,进行修改通常是相当困难的。大多数现代文件系统也(相当)比FAT复杂,这会给实现增加更多的困难。从理论上讲,它仍然是可能的——事实上,现在甚至思考它曾经在哪里是完全疯狂的。 几乎 合理。

        3
  •  2
  •   stefanB    15 年前

    我不确定你的文件的格式,但你可以把它“记录”为基础。

    • 将数据分块写入,并为每个块提供一个ID。
    • ID可以是文件中的数据偏移量。
    • 在文件的开头,你可以 有一个带有ID列表的标题,所以 你可以在里面读记录 秩序。
    • 在“ID列表”的末尾,您可以指向文件中存储另一个ID列表的另一个位置(以及ID/偏移量)。

    类似于文件系统的东西。

    要添加新数据,请在末尾附加它们并更新索引(向列表中添加ID)。

    您必须了解如何处理删除记录和更新。

    如果记录的大小相同,那么要删除记录,只需将其标记为空,然后下次使用相应的索引表更新将其重新使用。

        4
  •  0
  •   Emmanuel    15 年前

    如果使用.NET 4,如果您有类似应用程序的编辑器,请尝试使用内存映射文件-可能是JSUT。类似这样的事情(我没有把它键入vs,所以不确定是否语法正确):

    MemoryMappedFile bigFile = MemoryMappedFile.CreateFromFile(
       new FileStream(@"C:\bigfile.dat", FileMode.Create),
           "BigFileMemMapped",
           1024 * 1024,
           MemoryMappedFileAccess.ReadWrite);
    MemoryMappedViewAccessor view = MemoryMapped.CreateViewAccessor();
    int offset = 1000000000;
    view.Write<ObjectType>(offset, ref MyObject);
    
        5
  •  0
  •   MSalters    15 年前

    我注意到paxdiablo在处理其他应用程序方面的回答,以及matteo italia对可安装文件系统的评论。这让我意识到还有另一个非常重要的解决方案。

    使用重分析点,可以从基本文件和增量创建“虚拟”文件。任何不了解此方法的应用程序都将看到连续的字节范围,因为增量是由文件系统过滤器动态应用的。对于较小的增量(总计16 KB),增量信息可以存储在重分析点本身;较大的增量可以放在另一个数据流中。当然不平凡。

        6
  •  0
  •   zneak    12 年前

    也许最有效的方法是打电话给 ReadFileScatter() 要读取插入点前后的块,请将新数据插入 FILE_SEGMENT_ELEMENT[3] 名单和电话 WriteFileGather() . 是的,这涉及到在磁盘上移动字节。但是你把困难的部分留给了操作系统。