FileSystemWatcher 初始化后不触发事件,主因是路径非本地绝对路径或权限不足;文件写入未完成即触发需防抖处理;服务中易被GC回收,须强引用并校验目录存在。
FileSystemWatcher 初始化后不触发事件?检查路径和权限
最常见的现象是 filesystemwatcher 对象创建、enableraisingevents = true 也设了,但文件增删改一点反应都没有。根本原因往往不是代码逻辑错,而是路径或权限卡住了。
-
Path必须是本地绝对路径,不能是相对路径、UNC 路径(如\servershare)或网络映射盘符(如Z:),否则事件完全静默 - 监控目录需有读取+遍历权限;若监控子目录(
IncludeSubdirectories = true),父目录还需有“列出文件夹内容”权限 - 如果程序以管理员身份运行,而目标目录属普通用户(比如
C:UsersAliceDocuments),可能因 UAC 隔离导致监听失败 - 避免监控系统敏感路径(如
C:Windows),部分 Windows 版本会直接拦截事件通知
文件写入未完成就触发 Changed?用 NotifyFilter 和延迟缓冲
当程序写入一个大文件(如日志追加、Excel 导出),Changed 事件可能在文件还没写完时就触发,导致读取到截断或损坏内容。这不是 FileSystemWatcher 的 bug,而是 Windows 文件系统通知机制的固有行为。
- 默认
NotifyFilter包含LastWrite和Size,小文件频繁写入会反复触发;建议缩小范围,例如只监控FileName | DirectoryName+Attributes,再配合业务逻辑判断是否真要处理 - 对
Changed或Created事件,不要立刻打开文件——加个简单防抖:Task.Delay(100)后检查File.GetLastWriteTimeUtc(path)是否稳定,或尝试File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None)捕获IOException(说明还在被写入) - 避免在事件回调里做耗时操作(如解析 JSON、上传网络),否则会堆积事件队列,丢失后续通知
为什么 FileSystemWatcher 在服务中经常失效?生命周期和线程上下文是关键
把 FileSystemWatcher 放进 Windows Service 或后台线程后,事件突然停止,多数情况不是它“挂了”,而是对象被 GC 回收,或线程提前退出。
-
FileSystemWatcher实例必须被强引用住——不能定义为局部变量,也不能放在异步 lambda 里没捕获;推荐作为类字段(private readonly FileSystemWatcher _watcher)并确保所属对象长期存活 - 事件回调(
OnCreated等)运行在线程池线程上,不是 UI 线程,也不属于服务主线程;如果回调里调用了 WinForms/WPF 控件更新,必须用Invoke或Dispatcher.BeginInvoke - 服务启动时若目标目录不存在,
FileSystemWatcher不会报错,但也不会工作;务必在Start前先Directory.Exists(path)校验
跨平台替代方案:.NET 6+ 可用 FileSystemWatcher,但 Linux/macOS 行为差异大
.NET 5+ 确实让 FileSystemWatcher 能跑在 Linux/macOS 上,但底层依赖 inotify/kqueue,和 Windows 的 ReadDirectoryChangesW 完全不同,表现差异明显。
- Linux 下不支持监控符号链接目标内容(只监控链接本身),且
IncludeSubdirectories = true可能漏掉深层嵌套变动 - macOS 对 HFS+ 卷的事件延迟更高,有时多个操作合并成单次
Changed,ChangeType可能是Changed而非预期的Created - 如果项目明确要跨平台,别依赖
FileSystemWatcher的精确事件顺序;更稳妥的做法是定期轮询(如Timer+Directory.GetFiles哈希比对),虽然低效但可控
EnableRaisingEvents 的赋值时机,以及回调里有没有没 catch 住的异常(异常会终止当前事件线程,但不影响后续)。










