C#中如何将FileSystemWatcher的OnChanged事件检测的变更文件入队,按变更文件触发对应动作
多文件监听与专属动作绑定实现方案
核心逻辑基础
你现有代码的OnChanged事件回调本身就携带了变更文件的全部识别信息,根本不需要额外遍历文件夹定位变更源:
- 事件参数
FileSystemEventArgs e中的e.FullPath是变更文件的绝对完整路径,是可靠的文件唯一标识 e.Name是变更文件的短文件名(如A.txt)e.ChangeType标识触发事件的变更类型
你之前考虑用BlockingCollection做解耦的思路完全正确:FileSystemWatcher的事件由操作系统在线程池线程触发,高频变更容易打满内部缓冲区导致丢通知,用队列把变更信息暂存、由独立后台线程消费执行对应动作,能从根本上避免这个问题。
具体实现步骤
1. 先修复原有代码的隐藏问题
现有代码中FileSystemWatcher是Awake方法内的局部变量,方法执行结束后实例会被垃圾回收,后续文件变更不会触发事件,必须把watcher改成类级别的字段长期持有。
2. 构建文件与动作的关联映射
提前维护字典结构,将每个需要监听的文件全路径,和它对应的专属动作做绑定:
// 类级别的长期持有字段 private FileSystemWatcher _watcher; // BlockingCollection队列:暂存待处理的变更文件全路径 private BlockingCollection<string> _changeQueue = new BlockingCollection<string>(); // 文件-动作映射字典:key为文件全路径,value为对应的执行动作 private Dictionary<string, Action> _fileActionMap = new Dictionary<string, Action> { [@"C:\Path\to\folder\A.txt"] = ActionA, [@"C:\Path\to\folder\B.txt"] = ActionB };
3. 拆分事件监听与动作执行流程
事件回调只做“把变更文件路径丢入队列”这一件事,不直接执行业务动作;由独立的后台线程从队列中取出变更路径,匹配对应动作执行:
void Awake() { // 初始化watcher配置 _watcher = new FileSystemWatcher(@"C:\Path\to\folder") { NotifyFilter = NotifyFilters.LastWrite, Filter = "*.txt", IncludeSubdirectories = true, EnableRaisingEvents = true }; _watcher.Changed += OnChanged; // 启动独立后台线程消费队列任务 Task.Run(ConsumeChangeQueue); } // 队列消费逻辑 private void ConsumeChangeQueue() { // 从BlockingCollection中持续取出待处理的变更文件路径 foreach (var changedFilePath in _changeQueue.GetConsumingEnumerable()) { // 匹配对应绑定的动作 if (_fileActionMap.TryGetValue(changedFilePath, out var targetAction)) { try { targetAction.Invoke(); } catch (Exception ex) { Console.WriteLine($"执行{changedFilePath}关联动作失败:{ex.Message}"); } } } } // 变更事件回调:仅入队,不执行业务逻辑 private static void OnChanged(object sender, FileSystemEventArgs e) { // 可选的去重逻辑:避免同一文件短时间多次触发重复入队 if (!_changeQueue.Contains(e.FullPath)) { _changeQueue.Add(e.FullPath); } } // 各文件对应的专属动作示例 private static void ActionA() { Console.WriteLine("A.txt变更触发的动作a执行完成"); } private static void ActionB() { Console.WriteLine("B.txt变更触发的动作b执行完成"); }
新手实现注意点
- 识别文件时优先用
e.FullPath而非短文件名,因为你开启了IncludeSubdirectories = true,不同子目录下可能存在同名txt文件,仅靠短文件名会匹配错对应动作 - 不要在
OnChanged回调里直接执行耗时业务动作,否则容易导致FileSystemWatcher内部缓冲区溢出丢失事件,队列解耦的核心作用就是拆分监听流程和业务流程 - 一次文件写入操作通常会连续触发多次LastWrite事件,可以通过队列去重、增加短时间防抖窗口的方式,避免同一次文件修改重复触发多次动作
内容的提问来源于stack exchange,提问作者NewToCode
相关产品推荐
相关产品推荐

