当前位置:  开发笔记 > 开发工具 > 正文

Win32:写入文件而不缓冲?

如何解决《Win32:写入文件而不缓冲?》经验,为你挑选了2个好方法。

我需要创建一个新的文件句柄,以便对该句柄的任何写操作立即写入磁盘.

额外信息:句柄将是子进程的继承STDOUT,因此我需要该进程的任何输出立即写入磁盘.

研究CreateFile文档时,FILE_FLAG_WRITE_THROUGH标志看起来就像我需要的那样:

写操作不会通过任何中间缓存,它们将直接进入磁盘.

我写了一个非常基本的测试程序,好吧,它没有用.我在CreateFile上使用了标志,然后WriteFile(myHandle,...)在长循环中使用,在大约15秒内写入大约100MB的数据.(我添加了一些Sleep()).

然后,我建立了一个专业的监控环境,包括在资源管理器中持续点击"F5".结果:文件保持在0kB,然后在测试程序结束时跳转到100MB.

我尝试的下一件事是在每次写入后手动刷新文件FlushFileBuffers(myHandle).这使得观察到的文件大小变得美观和稳定,正如预期的那样.

我的问题是,那么,不应该FILE_FLAG_WRITE_THROUGH这样做没有手动刷新文件?我错过了什么吗?在"真实世界"程序中,我无法刷新文件,因为我无法控制正在使用它的子进程.

还有一个FILE_FLAG_NO_BUFFERING标志,我不能出于同样的原因使用 - 不能控制使用句柄的进程,因此我不能手动对齐此标志所需的写入.

编辑:我已经专门制作了一个单独的项目,用于观察文件大小的变化.它使用.NET FileSystemWatcher类.我也写了更少的数据 - 总共大约100kB.

这是输出.查看时间戳中的秒数.

'内置无缓冲区'版本:

25.11.2008 7:03:22 PM: 10230 bytes added.
25.11.2008 7:03:31 PM: 10240 bytes added.
25.11.2008 7:03:31 PM: 10240 bytes added.
25.11.2008 7:03:31 PM: 10240 bytes added.
25.11.2008 7:03:31 PM: 10200 bytes added.
25.11.2008 7:03:42 PM: 10240 bytes added.
25.11.2008 7:03:42 PM: 10240 bytes added.
25.11.2008 7:03:42 PM: 10240 bytes added.
25.11.2008 7:03:42 PM: 10240 bytes added.
25.11.2008 7:03:42 PM: 10190 bytes added.

......和'强制(手动)冲洗'版本(FlushFileBuffers()每隔~2.5秒调用一次):

25.11.2008 7:06:10 PM: 10230 bytes added.
25.11.2008 7:06:12 PM: 10230 bytes added.
25.11.2008 7:06:15 PM: 10230 bytes added.
25.11.2008 7:06:17 PM: 10230 bytes added.
25.11.2008 7:06:19 PM: 10230 bytes added.
25.11.2008 7:06:21 PM: 10230 bytes added.
25.11.2008 7:06:23 PM: 10230 bytes added.
25.11.2008 7:06:25 PM: 10230 bytes added.
25.11.2008 7:06:27 PM: 10230 bytes added.
25.11.2008 7:06:29 PM: 10230 bytes added.

Tim Lesher.. 12

在崩溃日志记录的背景下,我也被这种情况所困扰.

FILE_FLAG_WRITE_THROUGH只保证您发送的数据在返回之前被发送到文件系统WriteFile ; 它并不保证它实际发送到物理设备.因此,例如,如果在带有此标志的句柄上执行a ReadFile后,则WriteFile可以保证读取将返回您编写的字节,无论是从文件系统缓存还是从底层设备获取数据.

如果您想保证数据已写入设备,那么您需要FILE_FLAG_NO_BUFFERING所有随之而来的额外工作.例如,这些写入必须对齐,因为缓冲区在返回之前一直向下到设备驱动程序.

知识库有一篇关于差异的简洁但内容丰富的文章.

在您的情况下,如果父进程要比子进程长,那么您可以:

    使用CreatePipeAPI创建可继承的匿名管道.

    使用CreateFile创建一个文件FILE_FLAG_NO_BUFFERING集.

    将管道的可写句柄作为其STDOUT提供给子项.

    在父进程中,从管道的可读句柄读取到对齐的缓冲区,并将它们写入文件.


小智.. 5

这是一个老问题,但我想我可能会添加一些.其实我认为这里的每个人都错了.当您使用write-through和unbuffered-io写入流时,它会写入磁盘,但不会更新与文件系统关联的元数据(例如,资源管理器会向您显示).

你可以在这里找到关于这类东西的一个很好的参考资料http://winntfs.com/2012/11/29/windows-write-caching-part-2-an-overview-for-application-developers/

干杯,

格雷格



1> Tim Lesher..:

在崩溃日志记录的背景下,我也被这种情况所困扰.

FILE_FLAG_WRITE_THROUGH只保证您发送的数据在返回之前被发送到文件系统WriteFile ; 它并不保证它实际发送到物理设备.因此,例如,如果在带有此标志的句柄上执行a ReadFile后,则WriteFile可以保证读取将返回您编写的字节,无论是从文件系统缓存还是从底层设备获取数据.

如果您想保证数据已写入设备,那么您需要FILE_FLAG_NO_BUFFERING所有随之而来的额外工作.例如,这些写入必须对齐,因为缓冲区在返回之前一直向下到设备驱动程序.

知识库有一篇关于差异的简洁但内容丰富的文章.

在您的情况下,如果父进程要比子进程长,那么您可以:

    使用CreatePipeAPI创建可继承的匿名管道.

    使用CreateFile创建一个文件FILE_FLAG_NO_BUFFERING集.

    将管道的可写句柄作为其STDOUT提供给子项.

    在父进程中,从管道的可读句柄读取到对齐的缓冲区,并将它们写入文件.



2> 小智..:

这是一个老问题,但我想我可能会添加一些.其实我认为这里的每个人都错了.当您使用write-through和unbuffered-io写入流时,它会写入磁盘,但不会更新与文件系统关联的元数据(例如,资源管理器会向您显示).

你可以在这里找到关于这类东西的一个很好的参考资料http://winntfs.com/2012/11/29/windows-write-caching-part-2-an-overview-for-application-developers/

干杯,

格雷格

推荐阅读
mobiledu2402852357
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有