我如何观察并等待文件创建?

时间:2015-12-12 16:02:33

标签: c# .net winforms async-await filesystemwatcher

我正在使用FileSystemWatcher。 我正在通过按钮点击事件调用WatchDirectory。 然后我想在文件繁忙时显示“忙”并且当文件不忙时再分配到label6.Text以显示“不忙”。

使用async我不确定这是不是正确的方法。 等待这些方法我得到错误。

在WatchDirectory上我收到错误:

找不到'async'修饰符所需的所有类型。您是否针对错误的框架版本,或缺少对程序集的引用?

行上的相同错误:return await tcs.Task;

在WaitForUnlockedFile上我收到错误:

找不到'async'修饰符所需的所有类型。您是针对错误的框架版本,还是缺少对程序集的引用?

最后一次错误:

await Task.Delay(100);

'System.Threading.Tasks.Task'不包含'延迟'的定义

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

和WaitForUnlockedFile方法

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

1 个答案:

答案 0 :(得分:0)

因此,第一个关键点是,当文件系统事件在特定路径发生更改时,您可以使用FileSystemWatcher进行通知。例如,如果您希望在特定位置创建文件时收到通知,则可以找到。

接下来,我们可以创建一个方法,当文件系统观察程序触发相关事件时,使用TaskCompletionSource触发任务的完成。

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

请注意,首先检查文件是否存在,以便在适用时立即退出。它还使用创建的和重命名的处理程序,因为任一选项都可以允许文件在将来的某个时刻存在。 FileSystemWatcher也只监视目录,因此获取指定路径的目录然后检查事件处理程序中每个受影响文件的文件名非常重要。

另请注意,代码在完成后会删除事件处理程序。

这允许我们写:

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

Async wait for file to be created