我正在创建一个使用FileSystemWatcher的Windows应用程序。 FileSystemWatcher监视某些目录以进行更改。每次将某个文件添加到此目录中时,FileSystemWatcher必须将有关此文件的信息添加到XML文件中。一切正常,但是,当我添加,例如,同时添加100个文件(比如某些应用程序将这些文件添加到目录中)时,并非每个文件的信息都出现在此xml文件中。
我想使用Queue。并使用它来添加项目到这个集合。并使用计时器。计时器将从此集合向XML添加信息。这是好主意吗?
有人可以建议我做什么吗?
所以我认为我必须创建一个Windows应用程序和一个Windows服务。 WinApp只会向EventLog添加信息,Windows Service将读取信息EventLog并将其写入XML。我认为这是最好的方法。我在等待好的建议
答案 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的事件处理程序中,只需转到文件系统并获取目录的完整内容,无论事件告诉您什么?