如何确保所有数据都已物理写入磁盘?
据我所知,.NET FileStream的Flush方法只将当前缓冲区写入磁盘,但依赖于Windows的磁盘驱动程序和硬盘固件,这并不能保证数据实际上是物理写入磁盘。
是否有.NET或Win32方法可以给我这个保证? 因此,如果在调用此方法后一个纳秒时出现断电,我仍然可以确定一切正常吗?
在Windows下,查看FlushFileBuffers (Win32 API)。
Stefan S.说:
我知道.NET FileStream的Flush方法只将当前缓冲区写入磁盘
不,.NET FileStream的Flush只将.NET缓冲区写入OS缓存,它不会将OS缓存刷新到磁盘。 可悲的是,这个类的MSDN文档并没有这么说。 对于.NET <4.0,你必须调用Flush + Win32的FlushFilebuffers:
using System.Runtime.InteropServices; . . . // start of class: [DllImport("kernel32", SetLastError=true)] private static extern bool FlushFileBuffers(IntPtr handle); . . . stream.Flush(); // Flush .NET buffers to OS file cache. #pragma warning disable 618,612 // disable stream.Handle deprecation warning. if (!FlushFileBuffers(stream.Handle)) // Flush OS file cache to disk. #pragma warning restore 618,612 { Int32 err = Marshal.GetLastWin32Error(); throw new Win32Exception(err, "Win32 FlushFileBuffers returned error for " + stream.Name); }
对于.NET 4.0,您可以改为使用新的flush(true)方法。 11/09/2012更新: 这里的 MS错误报告说它已损坏,然后修复,但没有说它修复了什么版本或服务包! 听起来像bug是内部.NET FileStream缓冲区为空,Flush(true)什么也没做?
我注意到.NET 4 #Flush(true)实际上并没有写入磁盘。 我们遇到了数据损坏的奇怪问题,我在MS网站上发现了这个错误报告 :
错误报告的详细信息选项卡有一个可以运行的测试程序,可以显示问题;
- 将一堆数据写入磁盘
-
fs.Flush(true)
。 这不需要时间(比可能写入磁盘的速度快得多)。 - 使用win32 API
FlushFileBuffers
。 这需要很长时间。
我正在转换到win32 FlushFileBuffers调用…
好吧,你可以关闭文件…那可能会这样做。 实际上,由于HAL抽象,虚拟化和磁盘硬件现在拥有比几年前计算机更多的处理能力和缓存内存,因此您将不得不忍受希望磁盘完成其工作。
事务性文件系统从未真正实现过;-p当然,您可能会考虑使用数据库作为后端,并使用它的事务系统?
旁白:请注意,并非所有流甚至保证Flush()
– 例如, GZipStream
等保留了未提交数据的工作缓冲区,即使在刷新之后 – 让它冲洗所有内容的唯一方法是Close()
它。
在文件系统缓存中缓冲的文件数据将写入磁盘。 根据磁盘写头的位置,该数据通常是懒惰写入的。 拥有一千兆字节的缓存数据在技术上是可行的,因此可能需要一段时间。 如果这对您很重要,请考虑使用FileOptions.WriteThrough
选项。
只有太多的抽象级别才能绝对确保将数据写入光盘,直至硬件级别。
不是出色的表现或万无一失,但如果文件在单独的过程中写入并检查大小或内容,如何重新打开文件呢?
- 有没有办法将Console.Write的结果连续镜像到集合(数组,列表等)?
- 使用正则表达式c递归获取内部模式
- 检查列是否返回空值的最佳方法(从数据库到.net应用程序)
- 通过Windows服务运行时,操作不可用(从HRESULTexception:0x800401E3(MK_E_UNAVAILABLE))?
- 无法通过AppDomains传递GCHandle:没有代表的解决方案?
- 用于C#/ .NET API的向后兼容性的工具?
- File.Delete在之前调用Image.FromFile时失败,尽管复制了加载的图像并破坏了原始图像
- IEnumerable ,Arity和Generic Type Definitions
- 从父对象创建子对象实例的最佳方法