You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.28 17:06:07