【问题标题】:How can I watch a directory with a FileSystemWatcher and still allow for it to be properly deleted?如何使用 FileSystemWatcher 监视目录并仍然允许正确删除它?
【发布时间】:2014-10-28 01:26:57
【问题描述】:

考虑这段代码:

string dir = Environment.CurrentDirectory + @"\a";
Directory.CreateDirectory(dir);
FileSystemWatcher watcher = new FileSystemWatcher(dir);
watcher.IncludeSubdirectories = false;
watcher.EnableRaisingEvents = true;
Console.WriteLine("Deleting " + dir);
Directory.Delete(dir, true);
if (Directory.Exists(dir))
{
    Console.WriteLine("Getting dirs of " + dir);
    Directory.GetDirectories(dir);
}
Console.ReadLine();

有趣的是,这会在 Directory.GetDirectories(dir) 上引发 UnauthorizedAccessException。

删除监视目录返回没有错误,但 Directory.Exists() 仍然返回 true 并且该目录仍然列出。此外,访问该目录会为任何程序产生“拒绝访问”。一旦带有 FileSystemWatcher 的 .NET 应用程序退出,目录就会消失。

如何在允许正确删除目录的同时查看目录?

【问题讨论】:

    标签: c# .net filesystemwatcher


    【解决方案1】:

    您确实删除了该目录。但是直到引用它的最后一个句柄关闭,该目录才会从文件系统中物理删除。在两者之间打开它的任何尝试(就像您对 GetDirectories 所做的那样)都将失败并出现拒绝访问错误。

    文件存在相同的机制。查看 FileShare.Delete

    【讨论】:

    • 这是相当不令人满意的,因为它使无创监视目录成为不可能。但由于这是 Windows 的限制,我看不到解决办法。
    【解决方案2】:

    试试这条线:

     if (new DirectoryInfo(dir).Exists)
    

    代替:

    if (Directory.Exists(dir))
    

    【讨论】:

      【解决方案3】:

      您应该使用 FileSystemInfo.Refresh。 .Refresh() .Exists 后显示正确结果:

          var dir = new DirectoryInfo(path);
          // delete dir in explorer
          System.Diagnostics.Debug.Assert(dir.Exists); // true
          dir.Refresh();
          System.Diagnostics.Debug.Assert(!dir.Exists); // false
      

      【讨论】:

        【解决方案4】:

        不幸的是,FileSystemWatcher 已经获取了目录的句柄,这意味着当目录被删除时,仍然有一个指向标记为 PENDING DELETE 的目录的句柄。我已经尝试了一些实验,您似乎可以使用 FileSystemWatcher 中的错误事件处理程序来确定何时发生这种情况。

            public myClass(String dir)
            {
                mDir = dir;
                Directory.CreateDirectory(mDir);
        
                InitFileSystemWatcher();
        
                Console.WriteLine("Deleting " + mDir);
                Directory.Delete(mDir, true);
            }
            private FileSystemWatcher watcher;
        
            private string mDir;
        
            private void MyErrorHandler(object sender, FileSystemEventArgs args)
            {
                // You can try to recreate the FileSystemWatcher here
                try
                {
                    mWatcher.Error -= MyErrorHandler;
                    mWatcher.Dispose();
                    InitFileSystemWatcher();
                }
                catch (Exception)
                {
                    // a bit nasty catching Exception, but you can't do much
                    // but the handle should be released now 
                }
                // you might not be able to check immediately as your old FileSystemWatcher
                // is in your current callstack, but it's a start.
            }
        
            private void InitFileSystemWatcher()
            {
                mWatcher = new FileSystemWatcher(mDir);
                mWatcher.IncludeSubdirectories = false;
                mWatcher.EnableRaisingEvents = true;
                mWatcher.Error += MyErrorHandler;
            }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-02-07
          • 2015-05-24
          • 1970-01-01
          • 2013-01-18
          • 2015-06-18
          • 2021-10-13
          相关资源
          最近更新 更多