【问题标题】:FileSystemWatcher - event not firing the second timeFileSystemWatcher - 事件没有第二次触发
【发布时间】:2013-06-17 13:56:08
【问题描述】:

我有一个启动其他应用程序的应用程序,然后等待它们创建特定的数据文件(它一次监视一个应用程序)。每次启动应用程序时,它都会监视特定目录以查找要创建的特定文件。我正在使用 FileSystemWatcher 来执行此操作(将其设置为目录,然后过滤以获取正确的文件名)。这在第一次(总是)时效果很好,但第二个启动的应用程序永远不会触发事件。似乎触发事件的唯一方法是我在事件处理程序中放置一个断点,或者我在事件处理程序中有一个 Thread.Sleep 命令。这对我来说似乎很奇怪......是否有一些我不知道的比赛条件?这是代码。注意我有一个 Thread.Sleep(500)。使用这一行代码每次都有效。没有它就会失败。我真的不习惯依赖睡眠命令。我不确定什么条件会导致它无法正常工作。

    public static void watchFiles(string path)
    {
        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.Path = path;
        watcher.Created += new FileSystemEventHandler(watcher_Handler);
        watcher.EnableRaisingEvents = true;
   }

    public static void watcher_Handler(object sender, FileSystemEventArgs e)
    {
        //Hack - the sleep allows the second and third application to be caught by this event
        Thread.Sleep(500);

        switch (e.ChangeType.ToString())
        {
            case "Changed":
                break;
            case "Deleted":
                break;
            case "Created":
                if (e.Name == "log.dat")
                {
                    parseDataFile();
                    moveHTMLtoLMS();

                }
                break;
            default:
                break;
        }
    }

有人知道为什么我需要使用睡眠(或断点)来让代码再次运行吗?

【问题讨论】:

  • 注意:你不需要在开关中使用e.ChangeType.ToString(),只需打开e.ChangeType并制作案例ChangeType.XXX。这使其具有强类型且不易出错。
  • 文件系统观察者似乎有很多警告。 msdn.microsoft.com/en-us/library/…也就是说,你确定各个观察者看的不是同一个目录吗?
  • 顺便说一句,您可能需要发布操作系统和其他涉及的详细信息,例如这些是否是本地路径等。
  • 感谢关于 ChangeType 的说明。我确定目录是正确的。按预期运行和仅第一次运行之间的唯一区别是 Thread.Sleep。 p.s.我在 Windows 7 上使用本地路径。
  • 您确定 watcher.Created 注册在不存在断点的情况下多次发生在不同的目录上吗?添加日志行通常可以帮助调试这些类型的问题......因为设置断点会提供不同的结果......

标签: c# filesystemwatcher


【解决方案1】:

根据System.IO.FileSystemWatcher类的文档:

Windows 操作系统会在由 FileSystemWatcher 创建的缓冲区中通知您的组件。如果短时间内有很多变化,缓冲区可能会溢出。这会导致组件失去对目录更改的跟踪,并且它只会提供一揽子通知。使用 InternalBufferSize 属性增加缓冲区的大小是昂贵的,因为它来自无法换出到磁盘的非分页内存,因此请保持缓冲区小而大,以免错过任何文件更改事件。为避免缓冲区溢出,请使用 NotifyFilter 和 IncludeSubdirectories 属性,以便过滤掉不需要的更改通知。

可能是事件的消耗速度不够快,并且内部缓冲区不够大,无法处理所有通知。默认情况下,观察者处理FileNameDirectoryNameLastWrite 通知,但您只使用创建事件(文件和目录)。您的应用程序是否连续快速运行?我会尝试在应用程序的调用之间延迟(而不是事件处理程序),使用更具体的过滤器(只是FileName 通知或使用Filter 属性仅监视日志文件),增加内部缓冲区大小或以上任意组合。我认为这应该可以解决您的问题。

【讨论】:

  • 其他应用程序没有快速连续运行。在启动具有相同结果的不同应用程序之间,我可以等待几秒钟或几分钟。
  • @cwo:如果您尝试了我提到的其他方法,那么您也许可以避免延迟。
【解决方案2】:
public static void watchFiles(string path)
{
    FileSystemWatcher watcher = new FileSystemWatcher();
    watcher.Path = path;
    watcher.Created += new FileSystemEventHandler(watcher_Handler);
    watcher.EnableRaisingEvents = true;
}

watcher 变量可在此方法结束时进行垃圾回收。与其成为一个局部变量,不如让它成为一个类级别的成员:

private static FileSystemWatcher watcher;

public static void watchFiles(string path)
{
    if (watcher != null)
    {
        watcher.EnableRaisingEvents = false;
        watcher.Created -= new FileSystemEventHandler(watcher_Handler);
    }

    watcher = new FileSystemWatcher();
    watcher.Path = path;
    watcher.Created += new FileSystemEventHandler(watcher_Handler);
    watcher.EnableRaisingEvents = true;
}

【讨论】:

    【解决方案3】:

    您只收听一个“已创建”事件。你也需要听所有其他的 - OnChanged, OnDeleted - http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx

    编辑:当一个文件已经存在时,大多数程序不会“创建”文件。您可以使用 FileMon(现在的 Process Monitor - http://technet.microsoft.com/en-us/sysinternals/bb896645 )查看每个程序对您的文件执行的操作。

    【讨论】:

    • created 事件是我唯一感兴趣的事件。switch 语句中的其他情况一开始只是为了测试文件系统观察器。创建文件后,我需要对其进行解析。文件的工作方式永远不会被更改、删除或重命名(或者如果它们是我不关心的)。
    • 尝试使用进程监视器来验证您的假设 - 我怀疑其他程序没有执行“创建”操作......或者至少你会确定问题出在你的代码上,不带通知。
    • 我已验证该文件是在正确的位置创建的。我一直在使用流程资源管理器。但我也可以打开有问题的目录并查看文件正在创建中。
    • 您在 parseDataFile/moveHTMLtoLMS 中的代码是否有可能因访问被拒绝(或其他异常)而失败,因为该文件刚刚创建但尚未写入?它可以解释为什么等待一段时间(足以让程序写入文件并关闭它)使代码工作......
    【解决方案4】:

    我在这里遇到了完全相同的问题(运行 Windows XP)。你的 hack 解决了这个问题。我想添加一些可能相关的注释。

    在我的情况下,文件名始终相同:创建、删除、创建 C:\blah.txt 等等。另外,我正在使用一个技巧来隐藏我的应用程序:

    Integrator.StartMonitor(); // Start the file monitor!
    
    Form f = new Form();
    f.ShowInTaskbar = false;
    f.ShowIcon = false;
    f.StartPosition = FormStartPosition.Manual; 
    f.Location = new Point(-32000, -32000);
    
    f.Show();
    f.Hide();
    
    Application.Run();
    

    我的文件观察器在调试模式下或当我添加你的 sleep-hack 时工作。它看起来确实像 FileSystemWatcher 中的一个错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-22
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-27
      相关资源
      最近更新 更多