流编写器 在系统突然关闭时在文件末尾写入 NUL 字符

本文关键字:文件 NUL 字符 系统 突然 | 更新日期: 2023-09-27 18:36:20

我正在编写一些测试应用程序,以使用StreamWriter将一些文本写入文本文件。执行WriteLine方法时,系统突然关闭。重新启动计算机后,我观察到文件末尾有许多 NUL 字符。

我已经搜索了许多网站,包括MSDN,但没有找到这个问题的解决方案。

有人可以帮助我解决这个问题吗?

如果我们执行以下步骤,可以轻松重现:

  1. 创建 Windows应用程序并在其上放置一个按钮控件。

  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的电源关闭按钮。

  4. 重新启动 PC 并检查文件。它包含以下文本:

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

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

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

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

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

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

NULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNULNUL

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

流编写器 在系统突然关闭时在文件末尾写入 NUL 字符

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

这个问题没有绝对的解决方案。

我在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 问题

我知道

它看起来很恶心,但这是我解决问题所必须做的。只需在将字符串写入文件后放置以下代码即可。

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 行,代码将写入数组的所有元素减去最后一个元素(NUL 行)