编写大文件的最佳实践

Best practice for writing big files

我的项目需要写一个大文件。


我学到了什么:


我的代码片段:

[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);
    }
}

我的问题:

The file will be missing if the app crashes between File.Delete and File.Move. Can I avoid this?

据我所知,但你可以检测到它 - 如果你使用更可预测的文件名,你可以从中恢复。如果您稍微调整该过程以使用三个文件名,它会有所帮助:目标、"new" 文件和 "old" 文件。过程变为:

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

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

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

注意:我以前不知道 File.Replace,但我怀疑它 有效 只是一种更简单且可能更有效的方法来执行您已经在做的代码. (太棒了 - 使用它!)恢复过程仍然是一样的。

您可以使用 File.Replace 而不是删除和移动文件。如果出现硬故障(断电或类似情况),您将始终丢失数据,您必须考虑到这一点。