文件.WriteAllText未将数据刷新到磁盘

本文关键字:刷新 磁盘 数据 WriteAllText 文件 | 更新日期: 2023-09-27 18:18:25

我现在有3个报告用户的机器在使用我的软件时崩溃了。崩溃与我的程序无关,但当他们重新启动配置文件时,我的程序写的都是损坏的。

文件的写入方式没有什么特别之处,只需创建一个Json表示并使用File.WriteAllText()将其转储到磁盘

// save our contents to the disk
string json = JsonConvert.SerializeObject(objectInfo, Formatting.Indented);
// write the contents
File.WriteAllText(path, json);

我有一个用户发给我一个文件,长度看起来是正确的(~3kb),但内容都是0x00。

根据下面的帖子文件。WriteAllText应该关闭文件句柄,将所有未写入的内容刷新到磁盘:

在我的c#代码中,计算机是否等待直到输出完成才继续前进?

但是,正如Alberto在评论中指出的:

System.IO.File。WriteAllText完成后,将刷新所有文本到文件系统缓存,然后,它将被惰性写入驱动器。

所以我假设这里发生的事情是文件正在被清除并初始化0x00,但是当系统崩溃时数据还没有写入。

我正在考虑可能使用某种临时文件,所以过程将是这样的:

  1. 写入新内容到临时文件
  2. 删除原文件
  3. 将临时文件重命名为原始

我不认为这将解决问题,因为我认为Windows将只是移动文件,即使IO仍然悬而未决。

是否有任何方法可以强制机器将该数据转储到磁盘,而不是它决定何时执行该操作,或者可能是更新文件的更好方法?

更新:

根据@usr, @mikez和@llya luzyanin的建议,我创建了一个新的WriteAllText函数,它使用以下逻辑执行写入:

  1. 使用FileOptions创建包含新内容的临时文件。WriteThrough国旗
  2. 将数据写入磁盘(直到写入完成才返回)
  3. 文件。Replace将新临时文件的内容复制到实际文件中,并进行备份

使用该逻辑,如果最终文件加载失败,我的代码将检查备份文件并加载该文件

代码如下:

public static void WriteAllTextWithBackup(string path, string contents)
{
    // generate a temp filename
    var tempPath = Path.GetTempFileName();
    // create the backup name
    var backup = path + ".backup";
    // delete any existing backups
    if (File.Exists(backup))
        File.Delete(backup);
    // get the bytes
    var data = Encoding.UTF8.GetBytes(contents);
    // write the data to a temp file
    using (var tempFile = File.Create(tempPath, 4096, FileOptions.WriteThrough))
        tempFile.Write(data, 0, data.Length);
    // replace the contents
    File.Replace(tempPath, path, backup);
}

文件.WriteAllText未将数据刷新到磁盘

可以使用FileStream.Flush强制数据到磁盘。写入临时文件,并使用File.Replace自动替换目标文件。

我相信这是保证工作。文件系统提供的保证很弱。这些保证很少被记录下来,而且它们很复杂。

或者,如果可用,您可以使用事务性NTFS。可用于。net。

FileOptions.WriteThrough可以代替Flush,但是如果你的数据可以超过单个集群的大小,你仍然需要临时文件。