2010-09-25 22 views
4

我正在创建一个使用FileSystemWatcher的Windows应用程序。 FileSystemWatcher监视一些目录的变化。每次将某个文件添加到此目录中时FileSystemWatcher都必须将此文件的信息添加到XML文件中。所有的工作都很好,但是当我在同一时间添加100个文件(例如某些应用程序将这些文件添加到目录中)时,并不是每个文件的信息都出现在此xml文件中。FileSystemWatcher通知

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

任何人都可以告诉我该怎么做?


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

+1

'FileSystemWatcher'被称为是对这类东西的挑剔。 – 2010-09-25 06:05:30

+0

所以你可以建议 – AEMLoviji 2010-09-25 06:13:16

+0

谢谢阿萨夫拉维。我知道我的英语不够好。 – AEMLoviji 2010-09-25 07:58:42

回答

2

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

我看过一些其他的东西,你可以尝试,如果增加缓冲区大小没有帮助:

  • 如果您订阅的FileSystemWatcher通知事件,尽量保持你的事件处理程序短可能;即。确保执行不会停留太久。如果你必须为每个文件通知做相当数量的工作,你可以尝试启动一个单独的线程并在那里进行处理;您的事件处理程序可以很快返回调用方(并且文件通知将更快地从缓冲区/队列中移除)。

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

    这有一个主要缺点:手动检测文件是否被删除,重命名或创建是否不容易。你的程序将不得不保留最后一个目录列表,根据这个目录列表可以比较当前列表,找出发生了什么变化。

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

2

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

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

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

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

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

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

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

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

+0

谢谢我会测试它 – AEMLoviji 2010-09-25 06:20:19

1

如果我理解正确的话:你看目录,并在许多文件在同一时间得到补充你只看到其中的一些与FileSystemWatcher

你有没有试过如下:在OnCreated事件处理程序,只要到文件系统,并取得相应目录的完整内容,不管是什么情况告诉你?

+0

是的,这是个好主意。但在XML文件必须数据保存为:<?XML版本= “1.0” 编码= “UTF-8”> 952063 \ ETIden \ filename.xls 23分之9/ 2010上午11点30分03秒 952063 \ ETIden \ 952063.rar 2010年9月23日上午11点30分03秒 删除0和deleted1(表示文件952063 \ ETIden \ filename.xls已添加,但952063 \ ETIden \ 952063.rar已删除) – AEMLoviji 2010-09-25 06:17:14

+0

因此,XML文件实际上是文件系统更改日志。 – Reinderien 2010-09-25 06:20:26

+0

当然可以。在这个XML文件中,所有的日志都保存了 – AEMLoviji 2010-09-25 06:53:04

2

有一个在MSDN文档,可以帮助您更可靠地检测变化的关键注:

保持你的事件处理代码的短 越好。

我怀疑(但不知道肯定),这是因为文件系统事件在主线程观察家提出,让您花处理事件的任何时间创建了一个窗口,其中的变化可以不被发现。您描述解决方案的方式似乎是您在回调中执行I/O(写入您的XML更改日志文件),并且根据API中的条件,执行内联工作肯定会有太多工作要做文档。如果您有很多工作要做,请将事件交给另一个线程进行处理,以便您尽快恢复观看文件系统。

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

每对API的指导方针

而且 - 确保您过滤可能的事件集,只让叫回那些你绝对必须看到:

为了避免缓冲区溢出,使用NotifyFilterIncludeSubdirectories properties因此,您可以过滤掉 不需要的更改通知。