StreamWriter.Close() 生成空白文件后断电,为什么?

发布于 2024-08-04 08:43:14 字数 979 浏览 5 评论 0原文

好的,解释一下;我正在开发一个可能在任何时间点发生电源故障的系统,我正在测试的一个点是在我使用 StreamWriter 写出文件之后。下面的代码:

// Write the updated file back out to the Shell directory.
using (StreamWriter shellConfigWriter =
        new StreamWriter(@"D:\xxx\Shell\Config\Game.cfg.bak"))
{
    for (int i = 0; i < configContents.Count; i++)
    {
        shellConfigWriter.WriteLine(configContents[i]);
    }
    shellConfigWriter.Close();
}

FileInfo gameCfgBackup = new FileInfo(@"D:\xxx\Shell\Config\Game.cfg.bak");
gameCfgBackup.CopyTo(@"D:\xxx\Shell\Config\Game.cfg", true);

shellConfigWriter 的内容(字符串的 List)写入用作临时存储的文件,然后将其复制到原始文件上。现在,在该代码执行完毕后,断电,再次启动时,文件 Game.cfg 存在且大小正确,但完全空白。起初我认为这是由于硬盘驱动器上启用了写入缓存,但即使关闭它,它仍然会发生(尽管不太频繁)。

任何想法都会非常受欢迎!

更新:好的,所以在删除.Close()语句并在每次写入操作后调用.Flush()之后,文件仍然以空白结束。我可以更进一步,在创建新文件之前先创建原始文件的备份,然后我有足够的备份来进行完整性检查,但我认为这无助于解决根本问题(当我告诉它写入、刷新并关闭文件时......它没有!)。

Ok, so to explain; I am developing for a system that can suffer a power failure at any point in time, one point that I am testing is directly after I have written a file out using a StreamWriter. The code below:

// Write the updated file back out to the Shell directory.
using (StreamWriter shellConfigWriter =
        new StreamWriter(@"D:\xxx\Shell\Config\Game.cfg.bak"))
{
    for (int i = 0; i < configContents.Count; i++)
    {
        shellConfigWriter.WriteLine(configContents[i]);
    }
    shellConfigWriter.Close();
}

FileInfo gameCfgBackup = new FileInfo(@"D:\xxx\Shell\Config\Game.cfg.bak");
gameCfgBackup.CopyTo(@"D:\xxx\Shell\Config\Game.cfg", true);

Writes the contents of shellConfigWriter (a List of strings) out to a file used as a temporary store, then it is copied over the original. Now after this code has finished executing the power is lost, upon starting back up again the file Game.cfg exists and is the correct size, but is completely blank. At first I thought that this was due to Write-Caching being enabled on the hard drive, but even with it off it still occurs (albeit less often).

Any ideas would be very welcome!

Update: Ok, so after removing the .Close() statements and calling .Flush() after every write operation the files still end up blank. I could go one step further and create a backup of the original file first, before creating the new one, and then I have enough backups to do a integrity check, but I don't think it'll help to solve the underlying issue (that when I tell it to write to, flush and close a file... It doesn't!).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

烟若柳尘 2024-08-11 08:43:14

使用 FileStream 对象构造函数的 FileOptions 参数防止操作系统缓冲输出:

    using (Stream fs = new FileStream(@"D:\xxx\Shell\Config\Game.cfg.bak", FileMode.Create, FileAccess.Write, FileShare.None, 0x1000, FileOptions.WriteThrough))
    using (StreamWriter shellConfigWriter = new StreamWriter(fs))
    {
        for (int i = 0; i < configContents.Count; i++)
        {
            shellConfigWriter.WriteLine(configContents[i]);
        }
        shellConfigWriter.Flush();
        shellConfigWriter.BaseStream.Flush();
    }

Keep the OS from buffering the output using the FileOptions parameter of the FileStream object's constructor:

    using (Stream fs = new FileStream(@"D:\xxx\Shell\Config\Game.cfg.bak", FileMode.Create, FileAccess.Write, FileShare.None, 0x1000, FileOptions.WriteThrough))
    using (StreamWriter shellConfigWriter = new StreamWriter(fs))
    {
        for (int i = 0; i < configContents.Count; i++)
        {
            shellConfigWriter.WriteLine(configContents[i]);
        }
        shellConfigWriter.Flush();
        shellConfigWriter.BaseStream.Flush();
    }
时间海 2024-08-11 08:43:14

首先,您不必在那里调用 shellConfigWriter.Close()using 语句会处理它。为了防止电源故障,您可能需要调用 shellConfigWriter.Flush()


更新
您可能需要考虑的其他事情是,如果电源故障确实可能在任何时间发生,那么它可能发生在写入过程中,这样只有部分字节会写入文件。确实没有办法阻止这种情况。

为了防止出现这些情况,常见的过程是使用状态/条件标志文件。您可以使用文件系统上是否存在具有特定名称的零字节文件来告诉您的程序在恢复时在哪里再次拾取。然后,在您确定已达到该状态并完成前一个状态之前,您不会创建或销毁触发特定状态的文件。

这样做的缺点是,这可能意味着时不时地丢掉很多工作。但好处是,这意味着代码的功能部分看起来很正常:只需要做很少的额外工作即可使系统足够健壮。

First of all, you don't have to call shellConfigWriter.Close() there. The using statement will take care of it. What you might want to do instead to guard against power failure is call shellConfigWriter.Flush().


Update
Something else you might want to consider is that if a power failure can really happen at any time, it could happen in the middle of a write, such that only some of the bytes make it to a file. There's really no way to stop that.

To protect against these scenarios, a common procedure is to use state/condition flag files. You use the existence or non-existence on the file system of a zero-byte file with a particular name to tell your program where to pick up again when it resumes. Then you don't create or destroy the files that trigger a particular state until you are sure you've reached that state and completed the previous.

The downside here is that it might mean throwing a lot of work away now and then. But the benefit is that it means the functional part of your code looks like normal: there's very little extra work to do to make the system sufficiently robust.

灵芸 2024-08-11 08:43:14

您想要设置AutoFlush = true;

You want to set AutoFlush = true;

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文