【问题标题】:StreamWriter Writing NUL characters at the end of the file when system shutdown abruptlyStreamWriter 在系统突然关闭时在文件末尾写入 NUL 字符
【发布时间】:2012-06-10 10:25:31
【问题描述】:

我正在编写一些测试应用程序以使用StreamWriter 将一些文本写入文本文件。在执行WriteLine 方法时,系统突然关闭。重启机器后,我发现文件末尾有很多 NUL 字符。

我搜索了许多网站,包括 MSDN,但没有找到解决此问题的方法。

谁能帮我解决这个问题?

如果我们执行以下步骤,这可以很容易地重现:

  1. 创建 WindowsApplication 并在其上放置一个按钮控件。

  2. 在按钮单击事件处理程序中编写以下代码:

    private void button1_Click(object sender, EventArgs e)

     {
         string str = "Welcome to the C Sharp programming world with a test application using IO operations.";
         StreamWriter sw = new StreamWriter(fileName, true, Encoding.Unicode, str.Length);
         sw.WriteLine(str);
         sw.Close();        
     } 
    
  3. 运行应用程序并连续单击按钮(直到机器关闭才停止)并按下PC的Poweroff按钮。

  4. 重启电脑并检查文件。它包含以下文本:

通过使用 IO 操作的测试应用程序欢迎来到 C Sharp 编程世界。

通过使用 IO 操作的测试应用程序欢迎来到 C Sharp 编程世界。

通过使用 IO 操作的测试应用程序欢迎来到 C Sharp 编程世界。

通过使用 IO 操作的测试应用程序欢迎来到 C Sharp 编程世界。

通过使用 IO 操作的测试应用程序欢迎来到 C Sharp 编程世界。

欢迎使用使用 IO 操作的测试应用程序来到 C Sharp 编程世界。

NULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNUL

NUL 字符会出现在 Notepaad++ 中,而我们在普通记事本中看不到这些字符。

【问题讨论】:

  • 不确定会有多大帮助,但在收盘前执行 sw.Flush() 可能会有所帮助。不过UPS会更好。 :(

标签: c# streamwriter shutdown


【解决方案1】:

会发生这种情况。当您首先附加一个文件时,它的大小在目录中被纠正(这在 NTFS 中是事务性的),然后写入实际的新数据。很有可能如果您关闭系统,您最终会得到一个附加大量空字节的文件,因为数据写入不像元数据(文件大小)写入那样是事务性的。

这个问题没有绝对的解决办法。

【讨论】:

  • 我知道这是一篇旧帖子,但我找到了解决方案。可以设置缓冲区大小并禁用缓存,以便以合适的大小直接进入磁盘。
【解决方案2】:

我在 linux(在树莓上)上的 netcore 遇到了同样的问题。看起来它们是某种没有及时刷新的缓冲区。 (StreamWriter.Flush() 方法没有帮助)。

解决方法是将缓冲区大小设置为数据大小array.Length 并使用FileOptions.WriteThrough 禁用所有缓存(来自msdn:)

表示系统应该通过任何中间缓存写入 并直接进入磁盘。

string str = "Welcome to the C Sharp programming world with a test application using IO operations.";
byte[] data = new UTF8Encoding(true).GetBytes(str);
using (FileStream fs = new FileStream(fileName, FileMode.Append, FileAccess.Write,
                                FileShare.Read, data.Length, FileOptions.WriteThrough))
{                    
    fs.Write(data , 0, data.Length);
}

对于那些来自 C/C++ 的人,它设置了 posix 标志:

O_DIRECT 尽量减少与此之间的 I/O 的缓存影响 文件。一般来说,这会降低性能,但它在 特殊情况,例如当应用程序进行自己的缓存时。 文件 I/O 直接从用户空间缓冲区完成。

更多信息:SO question

【讨论】:

  • 如果WriteThrough 真的解决了这个问题,我会感到惊讶。它可能会减少机会,但我认为它不会使写入原子化。首先,增加文件大小,然后写入数据。我猜WriteThrough 在该序列之后会导致刷新。
【解决方案3】:

我知道这看起来很糟糕,但这是我解决问题所必须做的。将字符串写入文件后,只需输入以下代码即可。

var lines = System.IO.File.ReadAllLines(workingFile.FullName);

//Strip the "null line" from file
if (lines[lines.Length - 1].StartsWith("\0\0\0\0\0"))
{
    System.IO.File.WriteAllLines(workingFile.FullName, lines.Take(lines.Length - 1).ToArray());
}

它的作用是将文件中的所有行读取到一个数组中,如果最后一行是讨厌的 NUL 行,代码将写入 Array 的所有元素减去最后一个元素(NUL 行)

【讨论】:

    猜你喜欢
    • 2020-11-17
    • 1970-01-01
    • 1970-01-01
    • 2015-02-02
    • 2021-11-13
    • 2011-10-19
    • 2014-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多