动态创建FileSystemWatcher无法监控网络驱动器,求可行方案
我正在开发一款可监控多个文件夹的应用,参考了几个动态创建FileSystemWatcher的方案,但测试后发现这些方案仅能监控本地文件夹,无法监控网络驱动器。
我的动态实现代码如下:
public static void StartMultipleWatchers(string path) { string[] paths = path.Split(','); foreach (string folderPath in paths) { try { string folderPathtrim = folderPath.Trim(); WatchFile(folderPathtrim); } catch(Exception ex) { Logger.Error(ex); } } } private static void WatchFile(string monitoredDir) { FileSystemWatcher fsw = new FileSystemWatcher(monitoredDir, "*.gz"); fsw.Changed += new FileSystemEventHandler(OnChanged); fsw.Created += new FileSystemEventHandler(OnCreated); fsw.EnableRaisingEvents = true; fsw.IncludeSubdirectories = true; Logger.Info($"Started loop Monitor of Folder: {monitoredDir}"); } private static void OnCreated(object sender, FileSystemEventArgs e) { FileInfo fileInfo = new FileInfo(e.FullPath); string value = $"Created: {e.FullPath}"; Logger.Info(value); }
该方案仅对本地文件夹有效,或仅监控单个网络文件夹时有效。
之后我尝试了手动逐个创建FileSystemWatcher的方案:
public static void TestManualWatchers() { var fsw1 = new FileSystemWatcher(@"\\lap.org.com\tool_data_odp_ws\metrology\CIM\DATA_READY\"); var fsw2 = new FileSystemWatcher(@"C:\TestPath\"); fsw1.Changed += OnChanged; fsw1.Created += OnCreated; fsw1.EnableRaisingEvents = true; fsw1.IncludeSubdirectories = true; fsw2.Changed += OnChanged; fsw2.Created += OnCreated; fsw2.EnableRaisingEvents = true; fsw2.IncludeSubdirectories = true; Logger.Info($"Started watching manual double files"); }
此方案可正常监控本地和网络文件夹。
请问两种实现的差异是什么?是否存在可行的动态创建多个FileSystemWatcher的方法?
两种实现的核心差异
动态创建方案中,FileSystemWatcher实例是局部变量,在WatchFile方法执行完毕后,没有被外部引用持有,会被.NET的垃圾回收器(GC)标记为可回收对象并销毁。尤其是网络文件夹的监控依赖持续的连接,GC回收后连接断开,自然无法触发事件。
而手动创建方案中,fsw1和fsw2虽然也是方法内的局部变量,但如果方法所在的类实例或静态上下文被持续持有(比如应用主线程未退出),这些实例会被隐式保留,不会被GC回收,因此能持续正常工作。
另外,动态方案中给FileSystemWatcher指定了过滤条件"*.gz",而手动方案没有设置过滤,这也可能导致部分场景下动态方案看似“失效”(比如网络文件夹中创建的非gz文件不会触发事件),但这不是核心原因。
可行的动态创建解决方案
要让动态创建的FileSystemWatcher持续有效,核心是保留对每个实例的引用,避免被GC回收。具体修改如下:
- 定义静态集合存储所有监控器实例:
// 全局静态集合,持有所有监控器实例,防止被GC回收 private static List<FileSystemWatcher> _watchers = new List<FileSystemWatcher>();
- 在
WatchFile方法中,将创建的实例添加到集合:
private static void WatchFile(string monitoredDir) { FileSystemWatcher fsw = new FileSystemWatcher(monitoredDir, "*.gz"); fsw.Changed += OnChanged; fsw.Created += OnCreated; fsw.EnableRaisingEvents = true; fsw.IncludeSubdirectories = true; // 添加到集合保留引用 _watchers.Add(fsw); Logger.Info($"Started loop Monitor of Folder: {monitoredDir}"); }
- 可选:停止监控时清理资源:
public static void StopAllWatchers() { foreach(var watcher in _watchers) { watcher.EnableRaisingEvents = false; watcher.Dispose(); } _watchers.Clear(); Logger.Info("All watchers stopped."); }
修改后,动态创建的FileSystemWatcher实例会被集合持有,不会被GC回收,本地和网络文件夹都能正常监控。另外需确保应用有足够权限访问目标共享文件夹,且网络连接稳定。
内容的提问来源于stack exchange,提问作者Datboydozy

