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

时间:2010-03-07 21:53:32

标签: c++ windows winapi

在Windows中,可以通过API写入文件的中间而不会覆盖任何数据而不必在此之后重写所有内容吗?

如果有可能那么我相信它显然会破坏文件;在它变成一个严重的问题之前我可以做多少次?

如果不可能通常采取什么方法/解决方法?使用大(即千兆字节)文件,在插入点之后重写所有内容变得非常快。


注意:我不能避免写到中间。将应用程序视为用于大型文件的文本编辑器,用户在其中键入内容然后保存。我也无法将文件拆分成几个较小的文件。

6 个答案:

答案 0 :(得分:8)

如果您需要的中间结果是可以由编辑器以外的其他应用程序使用的平面文件,我不知道有任何方法可以执行此操作。如果要生成平面文件,则必须将其从更改点更新到文件末尾,因为它实际上只是一个顺序文件。

但斜体是有充分理由的。如果您可以控制文件格式,则可以选择一些选项。某些版本的MS Word具有快速保存功能,它们不会重写整个文档,而是将增量记录附加到文件末尾。然后,当重新读取文件时,它按顺序应用所有增量,以便您最终得到的是正确的文件。如果保存的文件必须立即用于另一个不理解文件格式的应用程序,这显然不起作用。

我建议将文件存储为文本。使用可以有效编辑和保存的中间表单,然后使用一个步骤将其转换为不常用的可用文本文件(例如,在编辑器退出时)。这样,用户可以节省尽可能多的费用,但耗时的操作不会产生太大的影响。

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

内存映射(而非加载)文件可能提供可加快速度的效率。你可能仍然需要重写到文件的末尾,但它会在操作系统的较低级别发生。

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

答案 1 :(得分:4)

现实的答案是否定的。您唯一真正的选择是从修改的角度重写,或构建一个更复杂的格式,使用类似索引的内容来告诉如何将记录安排到预期的顺序。

从纯粹的理论角度来看,你可以在恰当的情况下做到这一点。使用FAT(例如,但大多数其他文件系统至少具有一定程度的相似性),您可以直接操作FAT。 FAT基本上是组成文件的群集的链接列表。您可以修改该链接列表以在文件中间添加新群集,然后将新数据写入您添加的群集。

请注意,我说纯粹是理论上的。在完全不受保护的系统(如MS-DOS)下进行这种操作本来很困难,但接近合理。对于大多数较新的系统,完全进行修改通常会非常困难。大多数现代文件系统(也相当)比FAT更复杂,这将进一步增加实现的难度。理论上它仍然是可能的 - 事实上,现在它甚至完全是疯狂的,它曾经只是几乎合理。

答案 2 :(得分:2)

我不确定您的文件格式,但您可以将其设为“记录”。

  • 以块的形式编写数据并为每个块分配一个id。
  • Id可能是文件中的数据偏移量。
  • 您可以在文件的开头 有一个带有id列表的标题 你可以读取记录 顺序。
  • 在'ids列表'的末尾,您可以指向存储另一个ID列表的文件中的另一个位置(和id / offset)

与文件系统类似的东西。

要添加新数据,请在最后添加它们并更新索引(将id添加到列表中)。

您必须弄清楚如何处理删除记录和更新。

如果记录的大小相同,那么删除就可以将其标记为空,下次将其重新使用并对索引表进行适当的更新。

答案 3 :(得分:0)

如果你有一个类似编辑器的应用程序,如果使用.NET 4尝试一个内存映射文件 - 可能jsut是票。像这样的东西(我没有把它输入VS所以不确定我的语法是否合适):<​​/ p>

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);

答案 4 :(得分:0)

执行此操作的最有效方法(如果您真的想要这样做)可能是调用ReadFileScatter()来读取插入点之前和之后的块,将新数据插入{{{ 1}}列表,然后调用FILE_SEGMENT_ELEMENT[3]。是的,这涉及在磁盘上移动字节。但是你将硬件留给操作系统。

答案 5 :(得分:0)

我注意到paxdiablo在处理其他应用程序时的答案,以及Matteo Italia对可安装文件系统的评论。这让我意识到还有另一个非平凡的解决方案。

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