你有读写的异步版本(开始/结束函数),但没有删除(我可以告诉你)。这有什么原因吗?没有像读/写那样异步删除的理由吗?
使用线程来模拟异步行为与异步函数不同。很大的不同,确保你得到了感知的并行处理,但它并没有真正防止阻塞,其他线程仍然被阻塞等待文件 i/o 完成。真正的异步函数(开始/结束函数)在系统级别运行,它们将文件 i/o 排队,让应用程序继续,并让应用程序知道它何时准备好继续文件 i/o(允许您在等待文件 i/o 可用时做其他事情)。
你有读写的异步版本(开始/结束函数),但没有删除(我可以告诉你)。这有什么原因吗?没有像读/写那样异步删除的理由吗?
使用线程来模拟异步行为与异步函数不同。很大的不同,确保你得到了感知的并行处理,但它并没有真正防止阻塞,其他线程仍然被阻塞等待文件 i/o 完成。真正的异步函数(开始/结束函数)在系统级别运行,它们将文件 i/o 排队,让应用程序继续,并让应用程序知道它何时准备好继续文件 i/o(允许您在等待文件 i/o 可用时做其他事情)。
这会很有用。如果在断开连接的网络共享上删除,DeleteFile 最多可能需要 30 秒。
原因很可能是没有异步删除文件的原生函数。托管 API 通常是非托管 API 的包装器。
现在为什么没有原生的异步文件删除 API?原生异步删除很难在 Windows 上实现。DeleteFile
在伪代码中CreateFile
加上NtSetInformationFile(Disposition, Delete)
plus CloseHandle
。没有异步CreateFile
(在我看来是 Windows 中的设计错误)。NtSetInformationFile
只需在内核中的文件数据结构上设置一个标志。它不能是异步的。实际删除发生在最后一个句柄关闭时。我认为这可能会导致CloseHandle
阻塞,这是 Windows 中的另一个设计问题。没有 async CloseHandle
。
这个怎么样:
public static class FileExtensions {
public static Task DeleteAsync(this FileInfo fi) {
return Task.Factory.StartNew(() => fi.Delete() );
}
}
然后你可以这样做:
FileInfo fi = new FileInfo(fileName);
await fi.DeleteAsync(); // C# 5
fi.DeleteAsync().Wait(); // C# 4
该类File
不公开异步文件删除方法;但是,通过使用FileStream
该类,仍然可以利用提供的 13 个构造函数重载中的特定一个来执行异步文件删除。以下代码将异步删除文件:
using (new FileStream(Path, FileMode.Open, FileAccess.Read, FileShare.None, 1, FileOptions.DeleteOnClose | FileOptions.Asynchronous)) ;
我没有对它进行太多测试,因此您可能需要稍微修改一下用法。FileShare.None
(如果在删除期间不应阻止其他线程的文件访问,您可能需要更改为其他内容。)此外,由于此代码不返回 Task 的任何派生,因此使用该Task.Run
方法运行它可能是有效的。基本上,它执行的文件删除实际上在 I/O 级别上是异步的,因此在这种情况下将其卸载到线程池应该是可以的。
如果没有其他东西打开文件,打开FileStream
withFileOptions.DeleteOnClose
将导致 Windows 在流关闭时删除文件。如果您已经打开 aFileStream
进行异步读/写,这可能会对您有所帮助,但如果您需要等待删除完成它对您没有帮助(尽管根据 @JoelFan 等待File.Delete
完成并不能保证文件实际上已被删除)。
有趣的是,在针对网络共享进行测试时,似乎像这样打开流并且什么都不做比File.Delete
:
using (new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose)) { }
我可能是错的,但如果有人试图在跨线程操作上访问同一个文件,则需要阻止文件访问,直到删除操作完成。
也许是因为您自己也可以轻松地做到这一点?
var t = Task.Factory.StartNew(() => File.Delete("file.txt"));
// ...
t.Wait();