如何编写一个文件,然后读取它以验证其内容,确保获取的是磁盘上的内容而不是缓存的内容。

5
我正在使用本地/C++/Win32/MFC代码在Windows上通过MFC序列化保存文档文件。我在写入过程中插入了自己的CFile衍生类,使我可以访问数据在写入时。这使我能够计算数据的校验和(或散列等),因为数据正在写出到文件。
在文件保存后,我想提供验证文件的选项。想法是重新打开文件并读取其中的内容以验证校验和/散列值等。
然而,我想知道,在刚刚写入文件后,操作系统是否可能在我立即读回文件时给我未写入的数据。在这种情况下,测试并不能真正告诉我该文件在磁盘上看起来很好。
我的担忧是合理的吗?如果是,有没有办法避免这个问题?

写入文件。关闭句柄。填充无用缓冲区以强制刷新RAM。删除缓冲区。读取文件。(如果计算机的RAM大于虚拟进程空间,则无法工作) - Mooing Duck
@Ambeco,而且它会对机器上的任何其他进程产生可怕的影响。 - David Heffernan
我认为在这个过程中我不想填充RAM。 - Nerdtron
3个回答

5
如果您正在使用CFile,可以调用CFile::Flush来确保所有内容都被写入磁盘。根据文档所述。
virtual void Flush( );

强制将文件缓冲区中剩余的数据写入文件。

1
我的猜测是,就像所有其他文件抽象一样,这只是将程序缓存刷新到操作系统。不能保证这实际上会刷新到磁盘。 - edA-qa mort-ora-y
1
@edA-qamort-ora-y 但如果您使用另一个操作系统调用再次读取数据...它将始终是正确的。 - parapura rajkumar
1
@Nerdtron 只需刷新缓冲区。我的理解是,Windows 最终会告诉磁盘驱动程序将缓冲区刷新到磁盘上。如果磁盘驱动程序不这样做("性能优化"),那么你就无能为力了。我没有它的便利,但我相信 SQL Server 的 PSS 有几篇博客文章提到这个问题是日志文件损坏的主要原因之一。但基本上:告诉 Windows 刷新文件,它应该会刷新文件。除非磁盘驱动程序对其撒谎,否则 Windows 或你都无法检测到这种情况。 - ta.speot.is
1
@Nerdtron 我在MSDN上找不到任何保证文件在关闭时会被刷新的文档,但请注意Closevirtual - 你说你派生自CFile,所以也许可以重写CloseFlush(); CFile::Close(); - ta.speot.is
1
@Nerdtron 我已经有一段时间没有涉及MFC源代码了,但你可以进入CFile :: Close和CFile ::〜CFile并查看是否为您执行了刷新。 - parapura rajkumar
显示剩余4条评论

3
如果您真的想这么做,那么在打开文件时指定FILE_FLAG_NO_BUFFERING和/或FILE_FLAG_WRITE_THROUGH可以避免磁盘缓存和缓冲区。请注意,使用这些选项会使事情变得复杂。

使用CreateFile使用FILE_FLAG_NO_BUFFERING标志成功处理文件需要严格要求,详见文件缓冲

打开文件或设备时,数据读取和写入不进行系统缓存。此标志不影响硬盘缓存或内存映射文件。

更简单的替代方法是在关闭文件句柄之前调用FlushFileBuffers

1

我不知道这个问题的答案。但是,我知道在哪里寻找。

SQLite保证数据安全写入磁盘,无论发生什么情况-即使是断电。他们必须做你需要的事情,他们的代码是开源的,并且注释得非常好。

在SQLite中,单个事务中的所有更改要么完全发生,要么根本不发生,即使将更改写入磁盘的操作被

程序崩溃,

操作系统崩溃,

或者停电所打断。

上一段的声明在SQLite回归测试套件中得到了广泛检查,该套件使用特殊的测试工具模拟操作系统崩溃和停电对数据库文件的影响。

http://sqlite.org/transactional.html


有趣,谢谢你的提示!我会看一下他们的代码。 - Nerdtron
SQLite不能保证这一点,因为这是不可能的。除非有人发明出可以无需电源运行的磁盘!!! - David Heffernan
@David Heffernan 请阅读我在答案中发布的SQLITE保证。 - ravenspoint
你在回答中提到的保证并不是这样的。即使电源断掉,数据也会被写入磁盘。 - David Heffernan
@David Heffernan 我说的安全,意思是完全或者不行。 - ravenspoint
2
@ravenspoint 我相信这是因为SQLite在每个数据库中都保留了一个小日志,这是一个外部于操作系统的机制。请注意,保证并不是数据完全写入或者没有写入,而是更改完全写入或者没有写入。如果电源故障中断提交,文件中仍然可能存在垃圾,但是日志知道这一点。 - ta.speot.is

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接