【发布时间】:2010-09-27 20:29:20
【问题描述】:
我了解 .NET FileStream 的 Flush 方法只是将当前缓冲区写入磁盘,但依赖于 Windows 的磁盘驱动程序和硬盘固件,这并不能保证数据实际上是物理写入磁盘的。
有没有 .NET 或 Win32 方法可以给我这个保证?所以如果在调用这个方法回来后一纳秒掉电,我仍然可以确定一切正常吗?
【问题讨论】:
标签: c# .net filestream flush
我了解 .NET FileStream 的 Flush 方法只是将当前缓冲区写入磁盘,但依赖于 Windows 的磁盘驱动程序和硬盘固件,这并不能保证数据实际上是物理写入磁盘的。
有没有 .NET 或 Win32 方法可以给我这个保证?所以如果在调用这个方法回来后一纳秒掉电,我仍然可以确定一切正常吗?
【问题讨论】:
标签: c# .net filestream flush
Stefan S. 说:
我了解.NET FileStream 的 Flush 方法只将当前缓冲区写入磁盘
不,.NET FileStream 的 Flush 仅将 .NET 缓冲区写入操作系统缓存,它不会将操作系统缓存刷新到磁盘。遗憾的是,这门课上的 MSDN 文档并没有这么说。对于 .NET
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) 方法。 2012 年 9 月 11 日更新:MS 错误报告 here 说它已损坏,然后修复,但没有说明修复的版本或服务包!听起来错误是如果内部 .NET FileStream 缓冲区为空,则 Flush(true) 什么也没做??
【讨论】:
在 Windows 下,查看FlushFileBuffers(Win32 API)。
【讨论】:
嗯,你可以关闭文件......这可能会做到这一点。实际上,随着 HAL 抽象化、虚拟化和磁盘硬件现在拥有比 计算机 几年前更多的处理能力和缓存内存,您将不得不忍受希望磁盘完成它的工作.
事务文件系统从未真正实现过;-p 当然,您也许可以考虑使用数据库作为后端,并使用它的事务系统?
除此之外:请注意,并非所有流甚至都保证Flush() - 例如,GZipStream 等即使在刷新后仍保留未提交数据的工作缓冲区 - 使其刷新的唯一方法 一切 em> 是Close()它。
【讨论】:
我注意到 .NET 4 #Flush(true) 实际上并没有写入磁盘。我们遇到了数据损坏的奇怪问题,我在 MS 网站上找到了这个bug report:
错误报告的详细信息选项卡有一个您可以运行的测试程序来显示问题;
fs.Flush(true)。这不需要时间(比可能写入磁盘要快得多)。FlushFileBuffers。这需要很长时间。我正在切换到 win32 FlushFileBuffers 调用...
【讨论】:
文件系统缓存中缓冲的文件数据要写入磁盘。该数据通常是延迟写入的,基于磁盘写入头的位置。拥有千兆字节的缓存数据在技术上是可行的,因此可能需要相当长的时间。如果这对您很重要,那么请考虑使用 FileOptions.WriteThrough 选项。
【讨论】:
FILE_FLAG_WRITE_THROUGH 曾经被 SATA 驱动器损坏:disruptivesql.wordpress.com/2012/05/08/sata-and-write-through 我不知道目前的情况,但如果没有进一步的研究和测试,我不会相信它。跨度>
将缓冲区的内容刷新到磁盘有一个简单的答案。 在你的 WriteAllText 函数之后,打开文件,关闭它,然后重置它
这是一个例子
My.Computer.FileSystem.WriteAllText(yourfilename, "hello", False, System.Text.Encoding.ASCII)
FileOpen(1, yourfilename, OpenMode.Input)
FileClose(1)
Reset()
【讨论】:
抽象级别太多了,无法绝对确保将数据写入磁盘,一直到硬件级别。
不是出色的性能或万无一失,但是一旦在单独的过程中写入文件并检查大小或内容,如何重新打开文件?
【讨论】: