在外部进程(Win32)中创建文件时确保刷新文件

时间:2009-11-29 16:12:30

标签: c++ file winapi flush external-process

关于将文件活动刷新到磁盘的Windows Win32 C ++问题。

我有一个外部应用程序(使用CreateProcess运行),它创建了一些文件。即,当它返回时,它将创建一个包含一些内容的文件。

在继续操作之前,如何确保创建的进程真正刷新到磁盘?

我的意思是不是C ++缓冲区,而是真正刷新磁盘(例如FlushFileBuffers)。

请记住,我无法访问任何文件HANDLE - 这一切都隐藏在外部进程中。

我想我可以在文件中打开我自己的句柄,然后使用FlushFileBuffers,但不清楚这是否可行(因为我的句柄实际上并不包含任何需要刷新的东西)。

最后,我希望这在非管理员用户空间中运行,因此我无法在整个卷上使用FlushFileBuffers。

有什么想法吗?


更新:为什么我认为这是一个问题?

我正在研究数据备份应用程序。基本上它必须按照描述创建一些文件。然后它必须更新它的内部数据库(使用SQLite嵌入式数据库)。

我最近在蓝屏期间发生了数据损坏问题(其原因与我的应用程序无关)。

我担心的是系统崩溃期间的应用程序完整性。是的,我确实关心这个,因为这个应用程序是一个数据备份应用程序。

我关注的用例是:

  1. 使用外部流程创建小型数据文件。此写操作正在OS缓存中等待写入磁盘。
  2. 我更新数据库并提交。这是一个磁盘活动。此写操作也在OS缓存中等待。
  3. 发生系统故障。
  4. 在我看来,我们现在处于潜在的竞争状态。如果“1”被刷新而“2”没有被刷新那么我们就没事了(因为数据库交易没有提交)。如果两者都没有被冲洗或两者都被刷新,那么我们也没关系。

    据我了解,写入将是非确定性的。即,我不知道操作系统会保证在“2”之前写入“1”。 (我错了吗?)

    所以,如果“2”被刷新,但“1”没有,那么我们就有问题了。

    我观察到的是DB已正确更新,但文件中有垃圾:最后三分之二的数据是二进制“零”。现在,我不知道当你在蓝屏时刷新一个文件时看起来是什么样子,但如果看起来那样我也不会感到惊讶。

    我可以保证这是原因吗?不,我不能保证这一点。我只是猜测。它可能只是由于磁盘故障或蓝屏导致文件“自然”损坏。

    关于表现,这是我认为我可以处理的事情。

    例如,SQLite的默认行为是每次提交事务时执行完整文件刷新(使用FlushFileBuffers)。他们很清楚,如果你不这样做,那么在系统崩溃时,你可能会有一个损坏的数据库。

    另外,我相信只能通过“检查点”冲洗来减轻性能损失。例如,写入50个文件,刷新批次然后写入数据库。

    这有多大可能成为一个问题?甘拜下风。但是,我的应用程序很可能在系统故障时或其附近存档,因此您可能更有可能进行思考。

    希望这能解释我为什么不这样做。

3 个答案:

答案 0 :(得分:3)

你为什么要这样?操作系统将确保数据在适当的时候刷新到磁盘。如果您访问它,它将从缓存或磁盘返回数据,因此这对您来说是透明的。

如果您在发生灾难时需要一些安全措施,则必须致电FlushFileBuffers,例如在运行外部流程后创建具有管理员权限的流程。但这会严重影响整台机器的性能。

您唯一的其他选择是修改其他流程的来源。

[编辑]最简单的解决方案可能是复制你的进程中的文件,然后刷新副本(因为你有句柄)。将副本保存在“未在数据库中提交”的名称下。

然后更新数据库。写入数据库,“从文件更新...”。如果下次此条目已存在,请不要更新数据库并跳过此步骤。

将数据库刷新到磁盘。

将文件重命名为“文件已处理成数据库”。重命名是一个原子操作(所以它发生与否)。

如果你不能想到不同状态的好文件名,那么使用子文件夹并在它们之间移动文件。

答案 1 :(得分:2)

嗯,这里没有吸引人的选择。没有记录的方法来从流程中检索所需的文件句柄。虽然有undocumented ones,但只有仔细考虑才能去那里(通过DuplicateHandle)。

是的,在卷句柄上调用FlushFileBuffers是记录的方式。您可以通过让服务进行呼叫来避免权限问题。使用标准流程互操作机制之一与您的应用程序进行对话。名称以Global \为前缀的命名管道可能是最简单的方法。

答案 2 :(得分:0)

更新后,我认为http://sqlite.org/atomiccommit.html会为您提供所需的答案。

SQLite确保将所有内容刷新到光盘的方式。所以它也适合你 - 看一下来源。