13

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

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

4

5 回答 5

22

来自MSDN

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

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

另请参阅此相关问题:

FileSystemWatcher 在目录中同时添加多个文件时无法正常工作……</a>

更新:

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

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

如果您想更深入地了解修改缓冲区大小的成本,您应该在这里查看 Microsoft 的 Walter Wang 的帖子:

网络上的 FileSystemWatcher(下面引用的完整帖子)

很抱歉,FileSystemWatcher.InternalBufferSize 的文档在监控网络路径时没有非常清楚地说明缓冲区大小。监控网络路径时建议不要超过64K。

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

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

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

有与 .Net 应用程序相关的开销,我想 Win32 ReadDirectoryChangesW 程序可能能够在相同的缓冲区大小下实现更好的性能。然而,随着非常快速和大量的文件更改,缓冲区溢出将是不可避免的,并且开发人员将不得不处理发生溢出的情况,例如手动枚举目录以检测更改。

总之,FileSystemWatcher 和 ReadDirectoryChangesW 是一种轻量级的文件更改检测机制,但会有其局限性。Change Journals 是另一种我们认为是中等权重解决方案的机制,但仍然有局限性:

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

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

我希望以上解释可以帮助您了解您遇到的问题的根本原因。请回复让我们知道您是否需要更多信息。谢谢你。

于 2010-07-14T20:56:21.710 回答
4

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

于 2010-07-14T21:14:35.903 回答
2

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

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

于 2010-07-14T21:18:39.347 回答
0

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

于 2010-07-27T04:59:34.070 回答
-1

如果您使用 MacOSX + Parallels Desktop + Windows,您的代码不起作用,因为您的 FileSystemWatcher.Path 属性是针对 mac 路径的,它是 UNC 路径,不支持!

在此处输入图像描述

于 2018-01-13T00:55:34.717 回答