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

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

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

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

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

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

我不认为你可以。 我的意思是说你可能可以,但对我来说没有任何意义.-)

内存映射文件的全部重点在于它是实际文件的一个窗口。 如果你没有在文件中反映任何变化,你可能不得不做一些事情,比如在数据结构(例如,一个基地址,大小和数据的数组)中进行修改,并在保存时应用它们。

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

更新:

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

在加载时,您仍然需要将原始数据复制到临时文件,但是您不必将临时数据复制回来(无论是否保存),这将减少所需的时间。

可能,但不平凡。

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

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

所以,在你的情况下,你想使用写时复制模式。 如果用户决定放弃修改,没有问题。 您只需放弃内存映射。 所有在内存中修改的页面,都被丢弃。

如果用户决定保存,则您的任务稍微困难一些。 您现在需要确定文件的哪些部分已经更改。 这些变化在内存中,你需要重新应用这些到源文件。 你可以用PageGuards来做到这一点。 因此,当用户决定保存时,将所有修改后的页面复制到单独的内存块中,重新映射(不变)文件以进行写入,然后应用更改。