Почему нет асинхронного удаления файла в .net?
У вас есть асинхронные версии чтения и записи (функции begin/end), но не удаление (что я могу сказать). Есть ли причина для этого? Разве не так много причин для асинхронного удаления, как чтение/запись?
Использование потоковой обработки для имитации асинхронного поведения - это не то же самое, что асинхронные функции. Большая разница, конечно, вы получаете воспринимаемую параллельную обработку, но на самом деле это не предотвращает блокировку, что другой поток по-прежнему заблокирован, ожидая завершения ввода/вывода файла. Реальные асинхронные функции (начальные/конечные функции) работают на системном уровне, они ставят в очередь файл ввода/вывода, позволяют приложению продолжить работу и сообщают приложению, когда он готов продолжить работу с файлом i/o (позволяя вам делать другие вещи, пока вы ждете ввода/вывода файла).
Ответы
Ответ 1
Это было бы полезно. DeleteFile может занять до 30 секунд при удалении на отключенном сетевом ресурсе.
Вероятно, причина в том, что нет встроенной функции для асинхронного удаления файла. Управляемые API, как правило, являются обертками вокруг неуправляемых.
Теперь, почему нет собственного API удаления асинхронных файлов? Собственное асинхронное удаление трудно реализовать в Windows как есть. DeleteFile
делает в псевдокоде CreateFile
плюс NtSetInformationFile(Disposition, Delete)
плюс CloseHandle
. Там нет асинхронного CreateFile
(по моему мнению, ошибка дизайна в Windows). NtSetInformationFile
просто устанавливает флаг в структуре данных файла в ядре. Это не может быть асинхронным. Фактическое удаление происходит, когда последний дескриптор закрыт. Я думаю, что это может привести к блокировке CloseHandle
, что является еще одной проблемой проектирования в Windows. Там нет асинхронного CloseHandle
.
Ответ 2
Как насчет этого:
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
Ответ 3
Если ничего другого не открывается, открытие FileStream
с помощью FileOptions.DeleteOnClose
приведет к тому, что Windows удалит файл, когда поток будет закрыт. Это может помочь вам, если вы уже открываете FileStream
для асинхронного чтения/записи, хотя если вам нужно дождаться завершения удаления, это не поможет вам (хотя, согласно @JoelFan, ожидающего File.Delete
до конец не гарантирует, что файл на самом деле удаляется).
Интересно, что при тестировании на сетевом ресурсе кажется, что открытие потока как такового и ничего не делает с ним значительно быстрее (~ 40%), чем File.Delete
:
using (new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None, 4096, FileOptions.DeleteOnClose)) { }
Ответ 4
Класс File
не предоставляет асинхронный метод удаления файлов; однако с помощью класса FileStream
асинхронное удаление файла все еще можно выполнить, воспользовавшись определенной из 13 предоставленных перегрузок конструктора. Следующий код предположительно загрузит файл, установит его в ноль байтов, а затем удалит его; все асинхронно.
using (new FileStream(Path, FileMode.Truncate, FileAccess.ReadWrite, FileShare.Delete, 1, FileOptions.DeleteOnClose | FileOptions.Asynchronous)) ;
Я не очень много тестировал, поэтому вам, возможно, придется немного изменить использование. Кроме того, поскольку он не возвращает никаких производных от Task, вероятно, было бы правильным запустить его с помощью метода Task.Run
. По сути, он выполняет удаление файла, которое фактически асинхронно на уровне ввода/вывода, поэтому в этом случае его загрузка в пул потоков должна быть в порядке.
Ответ 5
Возможно, я ошибаюсь, но в случае, если кто-то пытается получить доступ к одному файлу при операции поперечного потока, потребуется блокировать доступ к файлу до завершения операции удаления.
Ответ 6
Возможно, потому, что вы можете так же легко сделать это сами?
var t = Task.Factory.StartNew(() => File.Delete("file.txt"));
// ...
t.Wait();