编写大文件的最佳实践

ter*_*ato 3 .net c# 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题:

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

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

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

Jon*_*eet 7

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

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

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

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

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

注意:我以前没有意识到File.Replace,但我怀疑它实际上只是一种更简单,可能更有效的方法来完成你已经在做的代码.(这很好 - 使用它!)恢复过程仍然是相同的.


110*_*110 5

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

  • 作为参考,`File.Replace()`的CLR实现使用[WinAPI方法`ReplaceFile()`](https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-胜基,replacefilea) (2认同)