0

An application needs a counter, which value to be stored in a text file. Sometimes it happens on very short intervals.

This test code rewrites a text file very often (f.e. every 100 milliseconds):

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();
    }
}

It works basically fine except in one of our "reliable tests" - stopping the computer electricity supply while the application is running.

The bad surprise was - in the file wasn't any text (should be a number) but only one or two space characters.

The missing last value it tries to write is understandable but making the file not consistent is really bad...

Trying the use of:

createFile.Flush();
createFile.Close();
createFile.Dispose();

GC.Collect();
GC.WaitForPendingFinalizers();

doesn't help.

4

5 回答 5

6

各种选择浮现在脑海中:-

1)保留当前文件的临时副本,例如重命名旧文件,写入新文件,删除旧文件(或用临时名称写入新文件,删除旧文件,重命名新文件),但也许您也在写出文件经常为了这种事情

2) 写入多个文件,并定期清理,例如 0001.txt、0002.txt、0003.txt 等,每 10 秒删除除最后一个文件之外的所有文件。

3)多次写入同一个文件,也许定期创建一个新文件,比如每10分钟一次,再次定期清理。

4) 使用第三方日志平台,例如 log4net,它可能可以防止断电等事件,并且可以记录到各种目标,例如文件、数据库、IRC

于 2009-01-29T12:08:25.260 回答
2

我认为最简单的做法是在 Windows Vista/2008 中使用事务文件系统:

http://www.michaelckennedy.net/blog/2007/12/07/SystemTransactionsAndWindowsVistaNTFSUpdated.aspx

http://msdn2.microsoft.com/magazine/2fc4ae05-f7b8-49d2-8630-f24bc9dfc2e6

也就是说,如果你是少数几个运行它的人之一......

于 2009-01-29T12:04:34.503 回答
1

您的文件缺少值,因为电源中断在 Windows 有机会将其刷新到磁盘之前将其关闭。您可以随心所欲地调用 Flush、Close、Dispose 等,但如果电源故障中断调用,它们将无法操作。充其量,它们会减少脆弱性的窗口。

我认为亚当拉尔夫的答案是最适合在任何系统上运行的答案。我投了他的票,但想加我的 0.02 美元,因为你的各种系统调用失败来纠正这个问题。

于 2009-01-29T13:03:04.853 回答
1

关闭文件系统分区中的“优化性能”。您正在写入文件,但 Windows 并不费心将数据写入物理磁盘,而是将其保存在内存中,以便最终写入,即。当有一些空闲时间。

显然你没有给它任何空闲时间:)

因此,关闭该标志并让 Windows 每次都将内容写入磁盘。这就像您用于闪存驱动器的同一标志,以确保在您将东西从 USB 端口中拉出之前实际写入数据。您可以强制 Windows 使用FlushFileBuffers API 调用写入数据。

或者您可以使用FILE_FLAG_WRITE_THROUGH选项。

显然,确保你的硬件也在写入数据——如果你有一个 RAID 卡,它会缓存数据写入本身,你需要一个电池来备份它以确保数据被物理写入驱动器。

我认为你不会对表演感到满意。最好的办法是使用电池支持的 RAID 卡写入磁盘。

于 2009-01-29T14:03:19.973 回答
0

谢谢大家的回答。

听他们说,现在的解决方案变成了:

使用 (FileStream createFile = new FileStream("Counter.txt", FileMode.Create, FileAccess.Write, FileShare.None, 8, FileOptions.WriteThrough)) {}

由于最后一个参数 - FileOptions.WriteThrough,所有参数都包含在内。其目的是避免使用各种现金、缓冲区、内存等。

由于此解决方案不提供 100% 的保证(由于硬件原因 :)),因此保留了备份。事实上,每次写入都会进行两次 - 在原始文件和备份文件中。

于 2009-01-29T15:15:07.677 回答