FileSystemWatcher用于通知

时间:2010-09-25 06:02:24

标签: c# notifications filesystemwatcher

我正在创建一个使用FileSystemWatcher的Windows应用程序。 FileSystemWatcher监视某些目录以进行更改。每次将某个文件添加到此目录中时,FileSystemWatcher必须将有关此文件的信息添加到XML文件中。一切正常,但是,当我添加,例如,同时添加100个文件(比如某些应用程序将这些文件添加到目录中)时,并非每个文件的信息都出现在此xml文件中。

我想使用Queue。并使用它来添加项目到这个集合。并使用计时器。计时器将从此集合向XML添加信息。这是好主意吗?

有人可以建议我做什么吗?


所以我认为我必须创建一个Windows应用程序和一个Windows服务。 WinApp只会向EventLog添加信息,Windows Service将读取信息EventLog并将其写入XML。我认为这是最好的方法。我在等待好的建议

4 个答案:

答案 0 :(得分:2)

FileSystemWatcher有一个内部缓冲区用于更改。当有很多快速更改时,缓冲区可能无法捕获所有事件。

尝试将InternalBufferSize增加到更高的值。

  

您可以将缓冲区设置为4 KB或更大,但不能超过64 KB。为获得最佳性能,请在基于Intel的计算机上使用4 KB的倍数。

     

系统通知组件文件更改,并将这些更改存储在组件创建的缓冲区中并传递给API。每个事件最多可使用16个字节的内存,不包括文件名。如果在短时间内有许多变化,缓冲区可能会溢出。这会导致组件无法跟踪目录中的更改,并且只会提供一揽子通知。增加缓冲区的大小有以下几点:

     

增加缓冲区大小可以防止丢失文件系统更改事件。请注意,由于与Windows操作系统的依赖性,FileSystemWatcher类的实例可能会在错过事件或超出缓冲区大小时引发Error事件。

     

增加缓冲区大小是昂贵的,因为它来自无法换出到磁盘的非分页内存,因此请尽可能减小缓冲区。要避免缓冲区溢出,请使用NotifyFilter和IncludeSubdirectories属性过滤掉不需要的更改通知。

对于诊断,也许您应该首先订阅Error Event以查看它是否真的是缓冲区溢出。

同样如上所述,将NotifyFilter设置为最小的必需标志,如果您只想跟踪更改,则可以是NotifyFilters.LastWrite

答案 1 :(得分:2)

正如Michael Stum在他的回答中写道,你可以尝试增加缓冲区大小(FileSystemWatcher.InternalBufferSize)。但请注意,您不应将此值设置为过高的值。此外,恕我直言,这可能只是一个临时修复,看看当你同时向文件夹中添加更多文件时会发生什么。

如果增加缓冲区大小没有帮助,我已经读过你可以尝试的其他一些事情:

  • 如果您订阅了FileSystemWatcher的通知事件,请尽量缩短您的事件处理程序;即。确保执行不会长久存在。如果你必须为每个文件通知做相当多的工作,你可以尝试启动一个单独的线程并在那里进行处理;然后,您的事件处理程序可以非常快速地返回调用者(并且文件通知将更快地从缓冲区/队列中删除)。

  • 除了基本通知之外,请勿使用FileSystemWatcher提供的任何其他信息。收到任何文件更改通知后,请等待一段时间,直到没有更多通知到达(即等待100个同时发生的文件更改通知中的最后一个通知)。然后手动列出目录的内容并将所需信息传输到XML。

    这有一个主要缺点:手动检测是否以及哪些文件已被删除,重命名或创建并不容易。您的程序必须保留最后一个目录列表,可以与当前列表进行比较,以找出更改的内容。

    这样做的好处是,您可以相当确定,由于某些FileSystemWatcher缓冲区溢出,不会删除任何更改。

答案 2 :(得分:2)

MSDN文档中有一个重要提示可以帮助您更可靠地检测更改:

  

保持您的事件处理代码简短   尽可能。

我怀疑(但不确定)这是因为文件系统事件是在主观察程序线程中引发的,因此每当您处理事件时,都会创建一个窗口,在该窗口中可以检测到更改。您描述解决方案的方式,似乎您在回调中执行I / O(对XML更改日志文件的写入),并且根据API中的条件,内联工作肯定太多了。文档。如果你有很多工作要做,请在一个单独的线程中处理你的事件以便处理,这样你就可以尽快回来看文件系统。

一个相对简单的方法就是使用ThreadPool.QueueUserWorkItem。这意味着您的更改日志仍然不会与文件系统的状态同步100%(由于使用单独的线程和队列引入的延迟),但它可能更准确,这似乎是您的主要关注点。您需要确保线程池调用的WaitCallback是线程安全的(例如,在没有lock()或类似情况的情况下,写入更改日志不会同时发生),并且请注意,不能保证更改日志条目将按照它们发生的顺序写入(尽管FileSystemWatcher是否保证这一点仍然令我怀疑。)

另外,根据API的指导原则 - 确保您正在过滤可能的事件集,因此您只能回复那些您绝对必须看到的事件:

  

为避免缓冲区溢出,请使用NotifyFilter和   IncludeSubdirectories properties所以你可以过滤掉   不需要的更改通知。

答案 3 :(得分:1)

如果我理解正确:您正在观看某个目录,并且当同时添加了多个文件时,您只能看到其中一些FileSystemWatcher

您是否尝试过以下操作:在OnCreated的事件处理程序中,只需转到文件系统并获取目录的完整内容,无论事件告诉您什么?