应用程序需要一个计数器,该值存储在文本文件中。有时它会在很短的时间内发生。
此测试代码经常重写文本文件(f.e.每100毫秒):
int counter = 0;
while (true)
{
WriteToFile(counter);
counter++;
Thread.Sleep(100);
}
private void WriteToFile(int counter)
{
byte[] buffer = Encoding.ASCII.GetBytes(counter.ToString());
using (FileStream createFile = new FileStream("Counter.txt", FileMode.Create))
{
createFile.Write(buffer, 0, buffer.Length);
createFile.Close();
}
}
除了我们的“可靠测试”之外,它的工作基本上都很好 - 在应用程序运行时停止计算机供电。
令人不快的是 - 在文件中没有任何文字(应该是数字)但只有一两个空格字符。
它尝试写入的最后一个值是可以理解的,但是使文件不一致真的很糟糕......
尝试使用:
createFile.Flush();
createFile.Close();
createFile.Dispose();
GC.Collect();
GC.WaitForPendingFinalizers();
无济于事。
答案 0 :(得分:6)
我想到了各种选择: -
1)保留当前文件的临时副本,例如重命名旧文件,写入新文件,删除旧文件(或用临时名称写新文件,删除旧文件,重命名新文件),但也许你为这种事情经常写出文件
2)写入多个文件,定期清理,例如0001.txt,0002.txt,0003.txt,...等等,每10秒删除除最后一个文件以外的所有文件。
3)多次写入同一文件,也许每隔10分钟定期创建一个新文件,再定期清理。
4)使用第三方日志记录平台,例如log4net,它可能可以防止电力中断等事情,并且可以记录到各种目标,例如:文件,数据库,IRC
答案 1 :(得分:2)
我认为最简单的方法是在Windows Vista / 2008中使用事务性文件系统:
http://www.michaelckennedy.net/blog/2007/12/07/SystemTransactionsAndWindowsVistaNTFSUpdated.aspx
http://msdn2.microsoft.com/magazine/2fc4ae05-f7b8-49d2-8630-f24bc9dfc2e6
也就是说,如果你是为数不多的人之一......
答案 2 :(得分:1)
您的文件缺少值,因为电源中断在Windows有机会将其清除到磁盘之前关闭了它。您可以根据需要调用Flush,Close,Dispose等,但如果电源故障中断了呼叫,它们将无法运行。充其量,他们将减少漏洞的窗口。
我认为Adam Ralph的答案是在任何系统上运行的最合适的答案。我投票支持他,但是想要在各种系统调用失败时加上我的0.02美元以纠正这个问题。答案 3 :(得分:1)
关闭文件系统分区中的“优化性能”。您正在编写该文件,但Windows并不打算将数据写入物理磁盘,而是将其保留在内存中,以便最终将其写入,即。当有空闲时间时。
显然你没有给它任何空闲时间:)
因此,关闭该标志并使Windows每次都将内容写入磁盘。这就像您用于闪存驱动器的相同标志,以确保在将数据从USB端口拉出之前实际写入数据。您可以强制Windows使用FlushFileBuffers API调用来编写数据。
或者您可以使用FILE_FLAG_WRITE_THROUGH选项。
显然,确保您的硬件也在写入数据 - 如果您有RAID卡,它将自动缓存数据写入,您需要备份电池以确保数据物理写入驱动器。
我认为你不会对表现感到满意。最好的办法是使用电池支持的raid卡写入磁盘。
答案 4 :(得分:0)
谢谢大家的答案。
听他们说现在的解决方案已成为:
使用(FileStream createFile = new FileStream(“Counter.txt”, FileMode.Create,FileAccess.Write,FileShare.None,8,FileOptions.WriteThrough)) {}
由于最后一个参数包含所有参数--FileOptions.WriteThrough。其目的是避免使用各种现金,缓冲,记忆等。
由于此解决方案不提供100%保证(由于硬件原因:))保留备份。事实上,每次写入都会完成两次 - 在原始文件和备份文件中。