Подтвердить что ты не робот

Почему нет асинхронного удаления файла в .net?

У вас есть асинхронные версии чтения и записи (функции begin/end), но не удаление (что я могу сказать). Есть ли причина для этого? Разве не так много причин для асинхронного удаления, как чтение/запись?

Использование потоковой обработки для имитации асинхронного поведения - это не то же самое, что асинхронные функции. Большая разница, конечно, вы получаете воспринимаемую параллельную обработку, но на самом деле это не предотвращает блокировку, что другой поток по-прежнему заблокирован, ожидая завершения ввода/вывода файла. Реальные асинхронные функции (начальные/конечные функции) работают на системном уровне, они ставят в очередь файл ввода/вывода, позволяют приложению продолжить работу и сообщают приложению, когда он готов продолжить работу с файлом i/o (позволяя вам делать другие вещи, пока вы ждете ввода/вывода файла).

4b9b3361

Ответ 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();