Почему в.net нет асинхронного удаления файла?
У вас есть асинхронные версии чтения и записи (функции начала / окончания), но не удаления (что я могу сказать). Есть ли причина для этого? Разве не так много причин делать асинхронное удаление, как чтение / запись?
Использование многопоточности для симуляции асинхронного поведения отличается от асинхронных функций. Большая разница, конечно, вы получаете воспринимаемую параллельную обработку, но на самом деле это не предотвращает блокировку, что другой поток все еще блокируется, ожидая завершения ввода-вывода файла. Настоящие асинхронные функции (функции начала / окончания) работают на системном уровне, они ставят в очередь файловый ввод-вывод, позволяют приложению продолжить работу и сообщают приложению, когда оно готово продолжить файловый ввод-вывод (что позволяет делать другие вещи, пока вы ждете, когда файл ввода / вывода станет доступным).
6 ответов
Это было бы полезно. DeleteFile может занять до 30 секунд при удалении на отключенном сетевом ресурсе.
Вероятно, причина в том, что нет встроенной функции для асинхронного удаления файла. Управляемые API обычно являются обертками вокруг неуправляемых.
File
класс не предоставляет асинхронный метод удаления файлов; однако за счет использования FileStream
класс, асинхронное удаление файла все еще может быть выполнено, используя преимущества одной из 13 предоставленных перегрузок конструктора. Следующий код предположительно загрузит файл, установит его в ноль байтов, а затем удалит его; все асинхронно.
using (new FileStream(Path, FileMode.Truncate, FileAccess.ReadWrite, FileShare.Delete, 1, FileOptions.DeleteOnClose | FileOptions.Asynchronous)) ;
Я не очень проверял это, поэтому вам, возможно, придется немного изменить использование. Кроме того, поскольку он не возвращает никаких производных от Task, вероятно, будет правильным запустить его с Task.Run
метод. По сути, он выполняет удаление файла, которое фактически асинхронно на уровне ввода / вывода, поэтому в этом случае его загрузка в пул потоков должна быть в порядке.
Как насчет этого:
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
Если ничто другое не открывает файл, открывая FileStream
с FileOptions.DeleteOnClose
заставит Windows удалить файл, когда поток будет закрыт. Это может помочь вам, если вы уже открываете FileStream
выполнять асинхронное чтение / запись, хотя, если вам нужно дождаться окончания удаления, это вам не поможет (хотя согласно @JoelFan ожидание File.Delete
завершение не гарантирует, что файл действительно удален в любом случае).
Интересно, что при тестировании с сетевым ресурсом кажется, что открытие потока как такового и ничего не делать с ним значительно быстрее (~40%), чем 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();