FileSystemWatcher 启动后 Created 事件触发两次是因编辑器保存机制导致;UNC/OneDrive 路径支持弱,需映射驱动器或轮询;文件占用需重试或共享模式打开;须订阅 Error 事件、增大缓冲区并及时释放资源。

FileSystemWatcher 一启动就触发两次 Created 事件
这是最常被当成 bug 的现象:新建一个文件,Created 事件却执行了两遍。不是监听出错,而是 Windows 文件系统本身的行为——多数编辑器(如 VS Code、记事本)保存时会先创建临时文件,再重命名覆盖原文件,或先写空文件再填充内容,导致底层触发多次 Created + Changed 组合。
实操建议:
- 别只监听
Created,优先用Changed配合ChangeType == WatcherChangeTypes.Changed和NotifyFilter = NotifyFilters.LastWrite - 加简单去重逻辑:记录文件
LastWriteTime或哈希,在事件回调里比对是否真有内容更新 - 避免在事件处理中直接读取刚创建的文件——可能仍被占用,抛
IOException: The process cannot access the file
监控网络路径或 OneDrive 同步文件夹失效
FileSystemWatcher 对 UNC 路径(如 \servershare)和云同步目录(OneDrive、Google Drive)支持极弱。它依赖 Windows 目录监视 API(ReadDirectoryChangesW),而这些路径往往不提供内核级变更通知,或仅在本地缓存层触发,延迟高、漏报多。
实操建议:
- 本地路径(
C:xxx)可用;UNC 路径必须映射为驱动器号(如Z:)才可能稳定,且需确保用户上下文一致(服务账户无法访问交互式用户的映射盘) - OneDrive/同步盘场景,改用轮询:
Directory.GetFiles()+FileInfo.LastWriteTime比对,间隔至少 2–5 秒,避免频繁 IO - 不要设置
IncludeSubdirectories = true监控整个 OneDrive 根目录——极易因数万文件触发Error事件并静默停止
事件回调里调用 File.ReadAllText 报“文件正由另一进程使用”
这不是 FileSystemWatcher 的锅,是典型的竞态条件:事件通知到达时,源程序(如 Excel、Photoshop)还没释放文件句柄。此时直接打开读取必然失败。
实操建议:
- 永远用
try/catch (IOException)包裹文件操作,失败后延迟重试(如Task.Delay(100)后再试,最多 3 次) - 改用共享模式打开:
new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite),能绕过部分独占锁 - 关键业务别在事件线程里做耗时操作——用
Task.Run(() => { ... })搬到后台线程,避免阻塞监听线程导致后续事件堆积
长时间运行后突然不触发事件,也不报错
FileSystemWatcher 是非托管资源封装,内部使用异步 I/O 完成端口。一旦未正确处置、或缓冲区溢出、或权限变化,它会静默停止工作,EnableRaisingEvents 仍为 true,但事件再也不会来。
实操建议:
- 务必订阅
Error事件,并在回调里打日志(哪怕只是Console.WriteLine(e.GetException().Message)),这是唯一能捕获缓冲区溢出(InternalBufferSize不够)或权限丢失的途径 - 设置足够大的缓冲区:
InternalBufferSize = 65536(默认 8KB),尤其监控子目录多、变更频繁的场景 - 不要 new 完就丢着不管——用
using或显式调用Dispose(),否则可能泄漏句柄;若需长期存活,考虑加心跳检查:watcher.NotifyFilter不变时,定期Refresh()重置底层句柄
真正难的不是写监听逻辑,是预判哪些路径、哪些操作、哪些用户环境会让它沉默——它不报错,也不说话,只悄悄停下。


















