代码之家  ›  专栏  ›  技术社区  ›  Alan Clark

内存映射文件可选写入?

  •  1
  • Alan Clark  · 技术社区  · 15 年前

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

    • 打开一个供书写,稍后决定不保存它
    • 打开阅读,稍后决定保存

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

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

    FMapHandle := CreateFileMapping(FFileHandle, nil, PAGE_READWRITE, 0, 2 * 65536, nil);
    FBasePointer := MapViewOfFile(FileMapHandle, FILE_MAP_WRITE, FileOffsetHigh,
    FileOffsetLow, NumBytes);
    
    2 回复  |  直到 15 年前
        1
  •  4
  •   paxdiablo    15 年前

    我觉得你做不到。我的意思是你 可以 能够,但对我来说没有任何意义:—)

    内存映射文件的关键是它是实际文件的一个窗口。如果您不希望更改反映在文件中,您可能需要执行一些操作,比如成批处理数据结构中的更改(例如,基地址、大小和数据的数组),并在保存时应用这些更改。

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

    更新:

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

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

        2
  •  2
  •   Peter Mortensen user1284631    15 年前

    可能,但不平凡。

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

    现在,这三种模式之间的区别在于如何在映射的页面上设置描述符。在所有情况下,您都可以访问页面。(第一种模式)。但是,如果您请求写访问权并随后对其进行写操作,则在第一次写操作时,页面将标记为可写和脏。然后,它可以被写回原始文件,由操作系统决定(第二种模式)。最后,有可能获得copy-on-write语义。您仍然只能从内存中对页面的只读访问开始。当你写它的时候,CPU仍然有故障,操作系统需要修复它。对于copy-on-write,修复是通过将更改的页面的备份存储设置为页面文件而不是原始映射文件来完成的。

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

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