Ожидание, чтобы система удалила файл - PullRequest
15 голосов
/ 21 февраля 2012

У меня была проблема с обновлением списка файлов после удаления файла. Когда я дал команду на удаление файла, возникла исключительная ситуация, поскольку метод обновления пытался получить доступ к файлу, который должен был быть удален.

После некоторых размышлений и отладки я пришел к выводу, что проблема в том, что системе требуется некоторое время для удаления файла. И я решаю это так:

//Deleting file
System.Threading.Thread.Sleep(2000);
//Refreshing list

и все работало нормально.

Мой вопрос

Есть ли более элегантный способ подождать, пока система удалит файл, а затем продолжить с кодом ...?

Ответы [ 7 ]

13 голосов
/ 03 ноября 2015

Это работает для меня:

public static void DeleteFile(String fileToDelete)
{
    var fi = new System.IO.FileInfo(fileToDelete);
    if (fi.Exists)
    {
        fi.Delete();
        fi.Refresh();
        while (fi.Exists)
        {    System.Threading.Thread.Sleep(100);
             fi.Refresh();
        }
    }
}

Я обнаружил, что большую часть времени цикл while не будет введен.

6 голосов
/ 31 августа 2016

Облегченный код для использования FileSystemWatcher , подписаться на его Deleted событие и ждать.

6 голосов
/ 21 февраля 2012

Самый элегантный способ, который я могу себе представить, - это использовать FileSystemWatcher и подписаться на его Deleted событие.

3 голосов
/ 09 июля 2015

Вот некоторый код, использующий FileWatcher. То, что мы хотим сделать, это

await Utils.DeleteDirectoryAsync("c:\temp\foo", recurse: true);

ниже это реализует

using System;
using System.IO;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;

namespace Utils
{
    internal class FileWatcher : IDisposable
    {
        readonly FileSystemWatcher _Watcher;

        public Subject<FileSystemEventArgs> Changed = new Subject<FileSystemEventArgs>();

        public FileWatcher( string file )
        {
            // Create a new FileSystemWatcher and set its properties.
            _Watcher = new FileSystemWatcher
                       {
                           Path = Path.GetDirectoryName(file),
                           NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
                                          | NotifyFilters.FileName | NotifyFilters.DirectoryName,
                           Filter =Path.GetFileName(file) 
                       };

            // Add event handlers.
            _Watcher.Changed += OnChanged;
            _Watcher.Created += OnChanged;
            _Watcher.Deleted += OnChanged;
            _Watcher.Renamed += OnChanged;

            // Begin watching.
            _Watcher.EnableRaisingEvents = true;
        }

        // Define the event handlers.
        private void OnChanged( object source, FileSystemEventArgs e )
        {
            Changed.OnNext(e);
        }


        public void Dispose()
        {
            _Watcher.Dispose();
        }
    }
}

и некоторые утилиты, использующие все вышеперечисленное.

public static class FileUtils
{
    public static IObservable<FileSystemEventArgs> ChangedObservable(string path)
    {
        if (path == null)
            return Observable.Never<FileSystemEventArgs>();

        return Observable.Using(() => new FileWatcher(path), watcher => watcher.Changed);
    }

    public static Task DeleteDirectoryAsync(string path, bool recurse)
    {
        var task = new TaskCompletionSource<Unit>();

        if (Directory.Exists(path))
        {
            ChangedObservable(path)
                .Where(f => f.ChangeType == WatcherChangeTypes.Deleted)
                .Take(1)
                .Subscribe(v => task.SetResult(Unit.Default));

            Directory.Delete(path, recurse);
        }
        else
        {
            task.SetResult(Unit.Default);
        }

        return task.Task;
    }
}
1 голос
/ 07 декабря 2017

Я всегда использовал это:

System.GC.Collect();
System.GC.WaitForPendingFinalizers();

См. здесь и здесь

0 голосов
/ 24 сентября 2013

Directory.Delete сгенерирует исключение при первой обнаруженной ошибке.Если вы хотите продолжить удаление как можно большего количества файлов и подкаталогов, то вам не следует использовать Directory.Delete и писать собственное рекурсивное удаление с блоками try / catch внутри циклов.Пример, когда вы можете захотеть сделать это, если вы пытаетесь очистить временные файлы, и один из файлов был заблокирован.

0 голосов
/ 21 февраля 2012

Удаление каталога с помощью Directory.Delete , в частности перегрузка, которая принимает 'рекурсивный' логический в NTFS, должна быть атомарной операцией с точки зрения вашей программы.Нет необходимости самостоятельно выполнять ручную обработку.

...