编写大文件的最佳实践

时间:2018-12-07 08:01:06

标签: c# .net system.io.file

我需要在项目中写入一个大文件。


我学到的东西:

  • 我不应该将大文件直接写入目标路径, 因为这样可能会留下不完整的文件,以防应用在编写时崩溃。

  • 相反,我应该写一个临时文件并移动(重命名)它。 (称为原子文件操作)


我的代码段:

[NotNull]
public static async Task WriteAllTextAsync([NotNull] string path, [NotNull] string content) 
{
    string temporaryFilePath = null;
    try {
        temporaryFilePath = Path.GetTempFileName();
        using (var stream = new StreamWriter(temporaryFilePath, true)) {
            await stream.WriteAsync(content).ConfigureAwait(false);
        }            

        File.Delete(path);
        File.Move(temporaryFilePath, path);
    }
    finally {
        if (temporaryFilePath != null) File.Delete(temporaryFilePath);
    }
}

我的问题:

  • 如果应用在File.DeleteFile.Move之间崩溃,文件将丢失。我可以避免吗?

  • 写大文件还有其他最佳实践吗?

  • 我的代码上有什么建议吗?

2 个答案:

答案 0 :(得分:7)

  

如果应用程序在File.Delete和File.Move之间崩溃,则文件将丢失。我可以避免吗?

我不知道,但是您可以检测到它-如果使用更可预测的文件名,则可以从中恢复。如果您稍微调整一下过程以使用三个文件名,则将有所帮助:目标文件,“新”文件和“旧”文件。该过程变为:

  • 写入“新”文件(例如foo.txt.new
  • 将目标文件重命名为“旧”文件(例如foo.txt.old
  • 将“新”文件重命名为目标文件
  • 删除“旧”文件

您将拥有三个文件,每个文件可能存在或不存在。当您开始读取新文件时,这可以帮助您检测情况:

  • 没有文件:没有任何书面数据
  • 目标:一切都好
  • 目标和新内容:写入新文件时应用程序崩溃
  • 目标和旧版本:应用无法删除旧文件
  • 新旧:应用程序在第一次重命名后但在第二次重命名之前失败
  • 这三个,或者只是旧的,或者只是新的:正在发生非常奇怪的事情!用户可能已干扰

注意:之前我没有意识到File.Replace,但是我怀疑它有效只是一种更简单,可能更有效的方式来处理已经在执行的代码。 (太好了-使用它!)恢复过程仍然相同。

答案 1 :(得分:5)

您可以使用File.Replace代替删除和移动文件。万一发生硬故障(断电或类似情况),您将永远丢失数据,您必须依靠它。