FileSystemWatcher和Windows 7

我正在编写一个监视网络目录并且正在运行Windows Server 2008计算机的工具,FileSystemWatcher的OnChanged事件正在被任何未使用Windows 7的计算机放置在网络驱动器上的文件中正确触发因为如果在Windows 7计算机上复制的文件数量超过19(同时),则不会发生任何事件,尽管如果文件是单独完成的,它会起作用。 有没有解决方法或者是Windows 7内核如何处理FSW事件?

只是为了澄清它适用于从XP机器复制的数千个文件。 (该软件仍在2008服务器机器上)。

来自MSDN :

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

如果增加缓冲区大小是不够的,并且您无法控制一次触发事件的文件数,则必须添加其他轮询。

另见相关问题:

当许多文件同时添加到目录时,FileSystemWatcher无法正常工作……

更新:

简单地增加缓冲区大小可能很诱人,但这应该小心。 事实上,在网络访问方面存在64k的限制。 FileSystemWatcher类使用下面的Windows API函数ReadDirectoryChangesW具有此限制:

当缓冲区长度大于64 KB并且应用程序正在通过网络监视目录时,ReadDirectoryChangesW失败并返回ERROR_INVALID_PARAMETER。 这是由于基础文件共享协议的数据包大小限制。

如果你想更深入地了解修改缓冲区大小的成本,你应该看一下微软的Walter Wang的post:

整个网络中的FileSystemWatcher (完整post引用如下)

对不起,FileSystemWatcher.InternalBufferSize的文档在监视网络路径时没有说清楚缓冲区大小。 监控网络路径时,建议不要超过64K。

FileSystemWatcher基本上是Win32 ReadDirectoryChangesW API的.Net包装器。 要使用ReadDirectoryChangesW,您可以创建并指定操作系统将使用更改填充的缓冲区。 但是,ReadDirectoryChangesW文档中未提及的内容(但在FileSystemWatcher文档中暗示)是文件系统创建内部内核缓冲区以临时存储更改信息,直到它有机会更新用户缓冲区。 创建的内核缓冲区的大小与ReadDirectoryChangesW中指定的大小相同,并在非分页池内存中创建。 每次创建/调用FileSystemWatcher / ReadDirectoryChangesW时,也会创建新的内核缓冲区。

内核内存池(分页和非分页)在系统地址空间中留出,供设备驱动程序和其他内核组件使用。 它们会根据需要动态增长和缩小。 通过转到任务管理器的“性能”选项卡,可以轻松查看池的当前大小。 这些池将动态增长,直到它们达到在引导时计算的最大值,并取决于可用的系统资源(主要是RAM)。 您不希望达到此最大值,否则各种系统服务和驱动程序将开始失败。 但是,这个计算出的最大值不容易获得。 要确定最大池大小,您需要使用内核调试器。 如果您对有关系统内存池的更多信息感兴趣,我建议您查看MSPress书籍Inside Windows 2000中的Solomon和Russinovich的第7章。

考虑到这一点,没有建议你可以使用什么尺寸的缓冲区。 系统池的当前和最大大小将随客户端而变化。 但是,对于每个FileSystemWatcher / ReadDirectoryChangesW缓冲区,您可能不应该超过64k。 这源于ReadDirectoryChangesW中记录的网络访问限制为64k的事实。 但最终您将不得不在各种预期的目标系统上测试应用程序,以便您可以调整缓冲区。

与.Net应用程序相关的开销,我认为Win32 ReadDirectoryChangesW程序可能能够以相同的缓冲区大小实现更好的性能。 但是,由于文件更改速度非常快,缓冲区溢出将不可避免,开发人员将不得不处理发生溢出的情况,例如手动枚举目录以检测更改。

总之,FileSystemWatcher和ReadDirectoryChangesW是一种轻量级文件更改检测机制,它将具有其局限性。 变更期刊是另一种我们认为是中等重量解决方案的机制,但仍有局限性:

http://msdn.microsoft.com/en-us/library/aa363798%28VS.85%29.aspx

重量级解决方案是编写一个专用的文件系统filter驱动程序,它位于文件系统堆栈中并监视文件系统更改。 当然,这将是最复杂的方法。 大多数病毒扫描程序,备份软件和文件系统监视实用程序(如filemon(www.sysinternals.com))都实现了筛选器驱动程序。

我希望上面的解释可以帮助您了解您遇到的问题的根本原因。 请回复告诉我们您是否需要进一步的信息。 谢谢。

经过多次尝试使用FileSystemWatcher后,我放弃了它。 它不会在错误的时间正确触发事件,不正确的类型。 老实说,我认为它是.net框架中最糟糕的类之一。 我总是编写自己的类来获取System.Timer,经过x毫秒后,它将手动检查目录,文件。 是的,它需要更多的工作,是的,它可以是一个轻微的PITA,但一旦你写了它,你可以在任何你想要的地方使用它。 我希望FileSystemWatcher像宣传的那样工作,但我从来没有发现它这样做。

触发FileSystemWatcher事件的大多数时候,我忽略了对象传递的文件,因为此列表可能不完整。

我只是遍历FileSystemWatcher对象正在监视的目录,并执行手动扫描以查找可能不在FileSystemWatcher缓冲区中的文件。 它不是很优雅,但它确保你不会错过任何文件。

这是一个非常不可靠的类,当文件高于某个阈值时,我在初始副本上发生了大约7次事件,然后当文件传输对话框完成后,我又得到了7个事件,这个问题出现在所有操作系统中支持FSW。 虽然Windows 7(还没有尝试过vista)仍然只能一个接一个地接受文件或者一次接受19个文件,而如果我将文件从XP机器放入网络驱动器,我可以一次读取数千个文件,没有任何问题。 这可能只是将ReadDirectoryChangesW从XP更改为7.过去的19个文件我无法触及任何事件,所以我想这将成为我工具的“function”。 如果有任何其他信息可以随时贡献。

如果你使用MacOSX + Parallels Desktop + Windows,你的代码不起作用,因为你的FileSystemWatcher.Path属性是mac Path的目标,它是一个UNC路径,它不受支持!

在此处输入图像描述