File.WriteAllText不会将数据刷新到磁盘

我有3个报告现在用户的机器崩溃,而使用我的软件..崩溃是不相关的我的程序,但是当他们重新启动configuration文件我的程序写入都是腐败的。

没有什么特别的文件如何被写入,只需创build一个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。

根据下面的文章File.WriteAllText应该closures文件句柄,将任何未写入的内容清除到磁盘:

在我的C#代码中,计算机是否等到输出完成后再继续?

但是,正如阿尔贝托在评论中指出的那样:

System.IO.File.WriteAllText完成时,会将所有文本都刷新到文件系统caching中,然后,它会被懒惰地写入驱动器。

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

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

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

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

有没有什么办法可以强制机器将这些数据转储到磁盘上,而不是决定什么时候做,或者更好的方式来更新文件?

更新:

基于@usr,@mikez和@llya luzyanin的build议,我创build了一个新的WriteAllText函数,使用以下逻辑执行写入操作:

  1. 使用FileOptions.WriteThrough标志创build带有新内容的临时文件
  2. 将数据写入磁盘(在写入完成之前不会返回)
  3. File.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); } 

Solutions Collecting From Web of "File.WriteAllText不会将数据刷新到磁盘"

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

我相信这是保证工作。 文件系统提供弱保证。 这些保证几乎没有记录,而且很复杂。

或者,您可以使用Transactional NTFS(如果可用)。 它可用于.NET。

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