编写大文件的最佳实践
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);
}
}
我的问题:
如果应用程序在 File.Delete
和 File.Move
之间崩溃,该文件将丢失。我可以避免这种情况吗?
写大文件还有其他最佳实践吗?
对我的代码有什么建议吗?
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
而不是删除和移动文件。如果出现硬故障(断电或类似情况),您将始终丢失数据,您必须考虑到这一点。
我的项目需要写一个大文件。
我学到了什么:
我不应该将大文件直接写入目标路径, 因为这可能会留下一个不完整的文件,以防应用程序在写入时崩溃。
相反,我应该写入一个临时文件并移动(重命名)它。 (称为原子文件操作)
我的代码片段:
[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.Delete
和File.Move
之间崩溃,该文件将丢失。我可以避免这种情况吗?写大文件还有其他最佳实践吗?
对我的代码有什么建议吗?
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
而不是删除和移动文件。如果出现硬故障(断电或类似情况),您将始终丢失数据,您必须考虑到这一点。