0

I'm using FileSystemWatcher. I'm calling the WatchDirectory from a button click event. Then i want assign to label6.Text once the file is busy to display "busy" and when the file is not busy any more to display "not busy".

And using async i'm not sure if it's the right way here. This wait the methods are i'm getting errors.

On WatchDirectory i'm getting the error:

Cannot find all types required by the 'async' modifier. Are you targeting the wrong framework version, or missing a reference to an assembly?

Same error on the line: return await tcs.Task;

On WaitForUnlockedFile i'm getting the error:

Cannot find all types required by the 'async' modifier. Are you targeting the wrong framework version, or missing a reference to an assembly?

And last error on :

await Task.Delay(100);

'System.Threading.Tasks.Task' does not contain a definition for 'Delay'

private async Task<string> WatchDirectory()
        {
            using (FileSystemWatcher watcher = new FileSystemWatcher())
            {
                TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();

                watcher.Path = SavePathTextBox.Text;
                watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size;
                watcher.Filter = "*.jpg";
                watcher.Changed += (sender, e) =>
                {
                    if (e.ChangeType == WatcherChangeTypes.Changed)
                    {
                        var info = new FileInfo(e.FullPath);
                        var theSize = info.Length;
                        label5.BeginInvoke((Action)(() =>
                        {
                            label6.Text = theSize.ToString();
                        }));
                    }
                    tcs.SetResult(e.FullPath);
                };
                watcher.EnableRaisingEvents = true;

                return await tcs.Task;
            }
        }

And the WaitForUnlockedFile method

private async Task WaitForUnlockedFile(string fileName)
    {
        while (true)
        {
            try
            {
                using (IDisposable stream = File.Open(fileName, FileMode.OpenOrCreate,
                    FileAccess.ReadWrite, FileShare.None))
                { /* on success, immediately dispose object */ }

                break;
            }
            catch (IOException)
            {
            }
            await Task.Delay(100);
        }
    }
Muhammed Albarmavi
  • 23,240
  • 8
  • 66
  • 91
  • What version of the .NET framework are you targeting? async/await are part of 4.5 but can be used in 4.0 and VS2012 in some cases. What version of Visual Studio are you using? – lukevp Dec 12 '15 at 16:11
  • You right i changed the .NET target to 4.5 and all the errors gone. Now how do i use it in the button click event ? I'm calling first the method WatchDirectory and after it WaitForUnlockedFile ? Or should i do it in another way ? – Sharondohp Sharonas Dec 12 '15 at 16:29

1 Answers1

2

So the first key point is that you can use a FileSystemWatcher to be notified when a file system event changes at a particular path. If you, for example, want to be notified when a file is created at a particular location you can find out.

Next, we can create a method that uses a TaskCompletionSource to trigger the completion of a task when the file system watcher triggers the relevant event.

public static Task WhenFileCreated(string path)
{
    if (File.Exists(path))
        return Task.FromResult(true);

    var tcs = new TaskCompletionSource<bool>();
    FileSystemWatcher watcher = new FileSystemWatcher(Path.GetDirectoryName(path));

    FileSystemEventHandler createdHandler = null;
    RenamedEventHandler renamedHandler = null;
    createdHandler = (s, e) =>
    {
        if (e.Name == Path.GetFileName(path))
        {
            tcs.TrySetResult(true);
            watcher.Created -= createdHandler;
            watcher.Dispose();
        }
    };

    renamedHandler = (s, e) =>
    {
        if (e.Name == Path.GetFileName(path))
        {
            tcs.TrySetResult(true);
            watcher.Renamed -= renamedHandler;
            watcher.Dispose();
        }
    };

    watcher.Created += createdHandler;
    watcher.Renamed += renamedHandler;

    watcher.EnableRaisingEvents = true;

    return tcs.Task;
}

So the first key point is that you can use a FileSystemWatcher to be notified when a file system event changes at a particular path. If you, for example, want to be notified when a file is created at a particular location you can find out.

Next, we can create a method that uses a TaskCompletionSource to trigger the completion of a task when the file system watcher triggers the relevant event.

public static Task WhenFileCreated(string path)
{
    if (File.Exists(path))
        return Task.FromResult(true);

    var tcs = new TaskCompletionSource<bool>();
    FileSystemWatcher watcher = new FileSystemWatcher(Path.GetDirectoryName(path));

    FileSystemEventHandler createdHandler = null;
    RenamedEventHandler renamedHandler = null;
    createdHandler = (s, e) =>
    {
        if (e.Name == Path.GetFileName(path))
        {
            tcs.TrySetResult(true);
            watcher.Created -= createdHandler;
            watcher.Dispose();
        }
    };

    renamedHandler = (s, e) =>
    {
        if (e.Name == Path.GetFileName(path))
        {
            tcs.TrySetResult(true);
            watcher.Renamed -= renamedHandler;
            watcher.Dispose();
        }
    };

    watcher.Created += createdHandler;
    watcher.Renamed += renamedHandler;

    watcher.EnableRaisingEvents = true;

    return tcs.Task;
}

Note that this first checks if the file exists, to allow it to exit right away if applicable. It also uses both the created and renamed handlers as either option could allow the file to exist at some point in the future. The FileSystemWatcher also only watches directories, so it's important to get the directory of the specified path and then check the filename of each affected file in the event handler.

Also note that the code removes the event handlers when it's done.

This allows us to write:

public static async Task Foo()
{
    await WhenFileCreated(@"C:\Temp\test.txt");
    Console.WriteLine("It's aliiiiiive!!!");
}

Async wait for file to be created

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
Muhammed Albarmavi
  • 23,240
  • 8
  • 66
  • 91
  • Muhammad but i don't have the file name to watch. The idea is to watch if/when a new file is created. For example if the directory empty or for example if i have 20 files already in the directory and if a new file start being created then watch this file and wait it to be finished. I don't have the file name yet. All i know is that the file will be jpg type in this case. I need somehow to watch when a new file is being created and watch it from 0kb untill the file is no more creating. So maybe to watch the file size like in my first example in the question. NotifyFilters.Size; – Sharondohp Sharonas Dec 12 '15 at 16:59
  • Muhammad somehow to detect/watch when a new file is being created then watch the file size grow in real time and when the file size stopped growing any more and the file is not locked any more somehow to check if i can use the file then to decide that the file is ready for use like o display it in a picture box. – Sharondohp Sharonas Dec 12 '15 at 17:00
  • Detecting file size changes should be simple, create a timer with interval of 1000 and store the file size. At the interval, compare the file sizes. If the sizes are different, restart the timer. If the size is the same, assume file is finished being written to, and no need to restart timer. 1 second should be long enough to detect file size changes, yeah? – torpid prey Mar 20 '20 at 13:07
  • Which will only work once you have the `filesystemwatcher` adequately detecting a new file of course... – torpid prey Mar 20 '20 at 13:09
  • @torpidprey it's been a long time since I wrote a line in c# if you have a better version of my answer you can add as another answer for help by improve mine – Muhammed Albarmavi Mar 20 '20 at 13:12
  • oops didnt even look at timestamp, I didn't realise questions at the top of the list were from 4 years ago, i'll pay more attention next time – torpid prey Mar 20 '20 at 23:31