C# System.IO.FileSystemWatcher 几点经验

作者: 来源: 日期:2011-11-6

1. BufferSize

Windows 操作系统使用 FileSystemWatcher 创建的一个内存缓冲区通知程序文件的修改信息,如果在很短的时间内有非常多的文件修改,这个缓冲区会溢出, 造成部分追踪丢失,并且 FileSystemWatcher 不会产生异常。加大 InternalBufferSize 属性值可以避免这种情况。

InternalBufferSize 默认值是 8K,可以设置的最小值是 4K,增加或减小 InternalBufferSize 最好用 4K 的整数倍。每一个事件通知需要使用 16 字节,并不包含文件名。InternalBufferSize 的内存来自 non-paged 内存,注意这部分内存资源比较宝贵。

使用 NotifyFilter、IncludeSubdirectories 属性减小 trace 范围,设置 filter 属性并不会影响进入缓冲区的事件通知,另外尽快的完成事件处理,也是避免缓冲区溢出造成事件丢失的一个措施。

2. 隐藏文件也会监控

3. 有些系统中,FileSystemWatcher 的事件里对长文件名使用 8.3 短文件名方式表示。

4. 如果多个 FileSystemWatcher 在监控同一个对象,在 Windows XP 在没有打 SP1 之前,Windows 2000 SP2 或之前的操作系统中,只会有一个 FileSystemWatcher 接收到通知;更新版本的操作系统中所有 FileSystemWatcher 都会收到通知。

5. 一次文件操作产生多个事件通知

某些文件操作可能会引发多个文件更改事件,例如新增文件、拷贝粘贴一个新的文件等。上面的示例代码使用 log4net 记录日志,用一个计数器记录事件编号,当 Copy 一个 xml 文件并粘贴到 c:\t 目录下时,从日志文件中可以看到会产生多个事件:一个 Created 和多个 Changed。微软的解释是文件系统的操作比较复杂,另外还有其它程序的影响(例如杀毒软件等)。

初步测试,Rename、Delete、New 只会触发一个事件,Save、Paste 时会有多个事件。

在某些项目中经常需要监控某个配置文件的修改,实时加载配置信息到程序中,这种情况下可以参考 log4net 的做法。通过一个计时器,在文件事件处理中让计时器延迟一段时间之后,再执行加载新的配置文件操作。这样可以避免对文件做一次操作触发了多个更改事件,而多次加载配置文件。

6. 有人想同时监控多种类型的文件,例如 *.xml + *.config,发现 Filter 属性不支持这种设置(只能够设置一种)。

这种情况下可以将 Filter 属性设成 *.*,在事件里用 if (e.FullPath.EndsWith(".xml") || e.FullPath.EndsWith(".config")) 自己判断过滤一下。记得 Filter 属性的设置并不会减少进入缓冲区的事件通知,因此上面的方法并不会带来多少性能损失。

7、多用户情况下,A 用户运行监控程序,B 用户在操作文件,A 用户能监控到吗?

能。

相关文章