Waiting for system to delete file

Lightweight code to use a FileSystemWatcher, subscribe to its Deleted event and wait.

void DeleteFileAndWait(string filepath, int timeout = 30000)
{
    using (var fw = new FileSystemWatcher(Path.GetDirectoryName(filepath), Path.GetFileName(filepath)))
    using (var mre = new ManualResetEventSlim())
    {
        fw.EnableRaisingEvents = true;
        fw.Deleted += (object sender, FileSystemEventArgs e) =>
        {
            mre.Set();
        };
        File.Delete(filepath);
        mre.Wait(timeout);
    }
}

This works for me:

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();
        }
    }
}

I find that most of the time, the while loop will not be entered.


Here is some code using the FileWatcher. What we want to be able to do is

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

the below implements it

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();
        }
    }
}

and some utils that take advantage of the above observable.

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;
    }
}

The most elegant way I can think of is using a FileSystemWatcher and subscribe to its Deleted event.