【问题标题】:FileSystemWatcher does not work properly when many files are added to the directory at the same timeFileSystemWatcher 在目录中同时添加多个文件时无法正常工作
【发布时间】:2009-10-15 13:43:33
【问题描述】:

同时向目录中添加多个文件时,FileSystemWatcher 无法正常工作...

Watcher 根本不会找到目录中的所有文件 - 仅当文件被逐一放置在文件夹中时 - 不会在同时将大量文件复制到文件夹时...

创建线程是解决问题的方法还是有其他方法来处理问题?

【问题讨论】:

  • 请记住,FileSystemWatcher 依赖于操作系统在文件被添加/修改/删除/等时发出信号。所以拥有多个实例并没有帮助。

标签: c# filesystemwatcher


【解决方案1】:

documentation on that class 详细说明了该问题:

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

因此,在这种情况下,线程可能对您没有多大帮助。您可能想要增加缓冲区大小(但它应该有多大可能取决于计算机的速度和磁盘本身)或通过设置适当的过滤器来限制您感兴趣的文件。

【讨论】:

  • 当然,另一种选择是额外轮询文件夹中的新文件和丢失的文件。
  • 我有时会低估 C#、.Net 等,因为微软世界的开发很容易(通过说“微软应该对我也这么想……”)并且表现得自大,所以不要阅读文档然后把几个小时花在像这样的小事情上,哈哈
  • @DirkVollmar 你会怎么做?您可以人为地为文件夹中已存在的文件重新引发事件吗?
【解决方案2】:

C# 对我来说是新手,我在同样的问题上苦苦挣扎了将近一周。我有这个:

    private void btnWatchFile_Click(object sender, EventArgs e)
    {
        //code to create a watcher and allow it to reise events...
    }

    //watcher onCreate event
    public void onCreated(object sender, FileSystemEventArgs e)
    {
        if (!updateNotifications )
        {
            stringBuilder.Remove(0, stringBuilder.Length);
            stringBuilder.Append(e.FullPath);
            stringBuilder.Append(" ");
            stringBuilder.Append(e.ChangeType.ToString());
            stringBuilder.Append("    ");
            stringBuilder.Append(DateTime.Now.ToString());
            updateNotifications = true;
        }
    }

    //timer to check the flag every X time
    private void timer_Tick(object sender, EventArgs e)
    {
        if (updateNotifications )
        {
            notificationListBox.Items.Insert(0, stringBuilder.ToString());
            updateNotifications = false;
        }
    }

我什至将计时器间隔设置为 1 毫秒,但仍然缺少一些新的文件事件。我试图从onCreated 事件内部更新notificationsListBox,但我总是遇到交叉引用错误。直到我发现观察者 onCreated 事件是在主方法线程之外的线程中执行的,所以,简而言之,这是我的解决方案:

我将public delegate void Action() 作为我的类的一个属性,然后使用InvokeonCreated 事件内部更新notificationsListBox。下一段代码:

    public void onCreated(object sender, FileSystemEventArgs e)
    {
        stringBuilder.Remove(0, stringBuilder.Length);
        stringBuilder.Append(e.FullPath);
        stringBuilder.Append(" ");
        stringBuilder.Append(e.ChangeType.ToString());
        stringBuilder.Append("    ");
        stringBuilder.Append(DateTime.Now.ToString());
        updateNotifications = true;
        Invoke((Action)(() => {notificationListBox.Items.Insert(0, stringBuilder.ToString());}));
    }

因此不再需要计时器及其代码。 这对我来说非常有用,我希望它适用于任何有类似情况的人。 最好的问候!!!

【讨论】:

    【解决方案3】:

    试试这样的。

    public MainWindow()
        {
            InitializeComponent();
    
            #region initialise FileSystemWatcher
            FileSystemWatcher watch = new FileSystemWatcher();
            watch.Path = folder;
            watch.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;
            watch.Filter = ext;
            watch.Changed += new FileSystemEventHandler(OnChanged);
            watch.Created += new FileSystemEventHandler(OnChanged);
            watch.EnableRaisingEvents = true;
            #endregion
    
        }
    
     private void OnChanged(object source, FileSystemEventArgs e)
        {
            Application.Current.Dispatcher.BeginInvoke((Action)delegate
            {
              // do your work here. If this work needs more time than it can be processed, not the filesystembuffer overflows but your application will block. In this case try to improve performance here.
            }, System.Windows.Threading.DispatcherPriority.Normal);
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-13
      • 1970-01-01
      • 1970-01-01
      • 2010-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多