代码之家  ›  专栏  ›  技术社区  ›  Alex

“可靠”的文件处理。网

  •  0
  • Alex  · 技术社区  · 17 年前

    应用程序需要一个计数器,该计数器的值存储在文本文件中。有时它会在很短的时间间隔内发生。

    此测试代码经常重写文本文件(即每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();
    

    没用。

    5 回复  |  直到 12 年前
        1
  •  6
  •   Adam Ralph    17 年前

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

    1) 保留当前文件的临时副本,例如重命名旧文件、写入新文件、删除旧文件(或使用临时名称写入新文件、删除旧文件、重命名新文件),但对于此类事情,您可能太频繁地写入文件

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

    3) 多次写入同一个文件,或者周期性地创建一个新文件,比如说每10分钟一次,再定期清理一次。

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

        2
  •  2
  •   Dave Markle    17 年前

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

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

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

    也就是说,如果你是少数几个管理它的人之一。。。

        3
  •  1
  •   Mark Brittingham    17 年前

    您的文件缺少值,因为电源中断在Windows将其刷新到磁盘之前将其关闭。你可以随意调用Flush、Close、Dispose等,但如果电源故障中断了通话,它们就无法运行。充其量,它们将减少漏洞窗口。

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

        4
  •  1
  •   gbjbaanb    17 年前

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

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

    所以,关闭该标志,让Windows每次都将内容写入磁盘。这就像你在闪存驱动器上使用的同一个标志,以确保在你将数据从USB端口取出之前,数据已经被写入。您可以强制Windows使用 FlushFileBuffers API调用。

    或者你可以用 FILE_FLAG_WRITE_THROUGH 选项

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

    不过我想你不会满意这场演出的。最好的办法是使用电池支持的raid卡写入磁盘。

        5
  •  0
  •   alex alex    17 年前

    谢谢大家的回答。

    听他们说,目前的解决方案是:

    使用(FileStream createFile=new FileStream(“Counter.txt”), 文件模式。创建、文件访问。写,文件共享。无,8,文件选项。书写 {}

    所有参数都包括在内,因为最后一个选项是文件选项。写一遍。它的目的是避免使用各种现金、缓冲区、内存等。

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