内存映射文件可选写入吗?

时间:2009-10-27 07:56:07

标签: windows delphi winapi memory memory-mapped-files

使用内存映射文件时,它似乎是只读或只写。我的意思是你不能:

      
  • 有一个开放的写作,后来决定不保存   
  • 已经开放阅读,后来决定保存

我们的应用程序使用可写内存映射文件来保存数据文件,但由于用户可能希望在不保存更改的情况下退出,因此我们必须使用用户实际编辑的临时文件。当用户选择保存更改时,原始文件将被临时文件覆盖,因此它具有最新更改。这很麻烦,因为文件可能非常大(> 1GB),复制它们需要很长时间。

我尝试了许多用于创建文件映射的标志组合,但似乎没有一个允许按需保存的灵活性。任何人都可以证实这是事实吗?我们的应用程序是用Delphi编写的,但它使用标准的Windows API来创建映射,在我们的例子中

FMapHandle := CreateFileMapping(FFileHandle, nil, PAGE_READWRITE, 0, 2 * 65536, nil);
FBasePointer := MapViewOfFile(FileMapHandle, FILE_MAP_WRITE, FileOffsetHigh,
FileOffsetLow, NumBytes);

2 个答案:

答案 0 :(得分:5)

我认为你不能。我的意思是你可能能够,但它对我没有任何意义: - )

内存映射文件的重点是它是实际文件的窗口。如果您没有反复在文件中进行更改,则可能需要执行诸如批量处理数据结构中的更改(例如,基址,大小和数据的数组)并在保存时应用它们。

在这种情况下,您实际上不会需要内存映射文件,只需读入并维护您想要更改的块(如果有可能进行多用户访问,请先锁定文件)。

更新

您是否考虑过在执行保存时删除原始文件并将临时文件重命名为原始文件名的可能性?这可能比将1G数据从临时复制到原始数据要快得多。这样,如果您不想保存它,只需删除临时文件并保留原始文件。

您仍需要在加载时将原始数据复制到临时文件中,但不必复制临时数据(无论是否保存) - 这样可以将时间减半。

答案 1 :(得分:3)

可能,但非平凡。

您必须了解内存映射基础知识,以及内存映射文件的三种模式之间的区别。两者都留出了部分虚拟地址空间,并在内部表中创建了映射条目。最初没有分配物理RAM。因此,当您尝试访问内存时,CPU出现故障并且操作系统必须修复。它通过将文件内容复制到RAM并将RAM映射到过程中的错误地址来实现。

现在,三种模式之间的区别在于如何在映射页面上设置描述符。在所有情况下,您都可以在页面上获得读取权限。 (第一种模式)。但是,如果您要求写访问权并随后写入,则在第一次写入时,页面将被标记为可写和脏。然后可以根据OS(第二模式)将其写回原始文件。最后,可以获得写时复制语义。您仍然只对内存中的页面具有读访问权限。写入时,CPU仍然出现故障,操作系统需要修复它。通过写时复制,可以通过将已更改页面的后备存储设置为页面文件而不是原始映射文件来完成该修复。

因此,在您的情况下,您希望使用copy-on-write模式。如果用户决定放弃修改,没问题。您只需丢弃内存映射。在内存中修改并由页面文件支持的所有页面也将被丢弃。

如果用户确定决定保存,那么你的任务就会稍微艰难一些。您现在需要确定文件的哪些部分已更改。这些更改在内存中,您需要将这些更改重新应用于源文件。您可以使用Page Guards执行此操作。因此,当用户决定保存时,将所有已修改的页面复制到单独的内存块,重新映射(未更改的)文件以进行写入,并应用更改。

相关问题