FileSystemWatcher监控UNC路径失效:是实现问题还是需替代方案?
问题描述
我开发了一个服务用于监控多个UNC路径,目标是监听指定文件夹,当有新的.gz文件创建时,触发独立的.NET控制台文件转换程序执行转换操作。当前实现的FileSystemWatcher逻辑仅对本地目录有效,无法正常监控UNC路径(示例路径:\\tooltypedir.companyname.com\somedir\topfolder\toolvariant\data_ready\)。现咨询:是我的FileSystemWatcher实现存在错误,还是有更可靠的替代方案?
核心代码
static List<String> filesInProgress = new List<string>(); static List<FileSystemWatcher> listOfWatchers = new List<FileSystemWatcher>(); protected override void OnStart(string[] args) { UserSettingsUtil.InitServiceSettings(); _applicationExeDir = UserSettingsUtil.TDX2KlarfExePath; _tdx2KlarfExeName = UserSettingsUtil.TDX2KlarfApplicationExeName; _foldersToWatch = UserSettingsUtil.FoldersWatched; Watch(); }
监控逻辑代码
private static void Watch() { string[] paths = _foldersToWatch.Split(','); foreach (string dir in paths) { string dirTrim = dir.Trim(); if (Directory.Exists(dirTrim)) { FileSystemWatcher fileWatcher = new FileSystemWatcher(); fileWatcher.Path = dirTrim; fileWatcher.Created += File_Created; //fileWatcher.Changed += OnChanged; fileWatcher.Filter = "*.gz"; fileWatcher.IncludeSubdirectories = true; fileWatcher.EnableRaisingEvents = true; Logger.Info($"Started service monitoring {dirTrim}"); listOfWatchers.Add(fileWatcher); } } } private static void File_Created(object sender, FileSystemEventArgs e) { if (e.ChangeType == WatcherChangeTypes.Created) { if (Directory.Exists(e.FullPath)) { foreach (string file in Directory.GetFiles(e.FullPath)) { var eventArgs = new FileSystemEventArgs( WatcherChangeTypes.Created, Path.GetDirectoryName(file), Path.GetFileName(file)); //Logger.Info($"Inner Loop file create {file}"); File_Created(sender, eventArgs); } } else { var fullFilePath = e.FullPath; Logger.Info("{0} created.", fullFilePath); if (!filesInProgress.Contains(fullFilePath)) { Thread converter = new Thread(ConfigureAndStartProcess); converter.Start(fullFilePath); filesInProgress.Add(fullFilePath); } } } }
服务停止逻辑代码
protected override void OnStop() { //watcher.Dispose(); if (listOfWatchers.Count > 0) { foreach (var dirWatcher in listOfWatchers) { dirWatcher.Dispose(); } } }
解决方案分析
一、现有FileSystemWatcher实现的问题排查
FileSystemWatcher本身支持UNC路径,但你的代码存在几个可能导致监控失效的问题:
权限不足
- 若服务以本地系统账户运行,访问UNC路径时大概率没有足够权限。需将服务运行账户改为拥有目标UNC路径读写权限的域账户或本地账户。
- 验证方式:用服务运行账户手动登录系统,确认能正常访问、读写目标UNC路径下的文件。
Created事件的局限性
- 网络文件复制到UNC路径时,
Created事件可能在文件未完全写入时就触发,后续处理会出错;部分SMB网络文件系统对Created事件的通知支持不稳定,容易丢事件。 - 代码中递归调用
File_Created处理子目录文件,存在重复触发或栈溢出风险。
- 网络文件复制到UNC路径时,
未处理错误事件
- 监控UNC路径时易出现网络中断、权限变化等错误,你未订阅
Error事件,无法排查具体故障。建议添加:
配套实现错误日志记录:fileWatcher.Error += OnWatcherError;private static void OnWatcherError(object sender, ErrorEventArgs e) { Logger.Error($"监控器错误: {e.GetException().Message}"); }
- 监控UNC路径时易出现网络中断、权限变化等错误,你未订阅
线程安全问题
List<string>并非线程安全集合,多线程操作filesInProgress会引发异常或数据错误,建议改用ConcurrentDictionary<string, object>:
修改判断逻辑:static ConcurrentDictionary<string, object> filesInProgress = new ConcurrentDictionary<string, object>();if (filesInProgress.TryAdd(fullFilePath, null)) { Thread converter = new Thread(ConfigureAndStartProcess); converter.Start(fullFilePath); }
二、更可靠的替代方案
若原生FileSystemWatcher的网络稳定性无法满足需求,可考虑以下方案:
1. 定时轮询目录
实现简单、稳定性高,适合对实时性要求不极致的场景:
- 每隔固定时间(如10秒)扫描目标UNC路径及其子目录,对比上次扫描的文件列表,筛选新增的
.gz文件。 - 用
HashSet<string>存储已处理文件路径,避免重复操作。 - 注意:扫描大目录时需优化性能,避免阻塞服务主线程。
2. 使用第三方优化库
- Microsoft.Extensions.FileSystemGlobbing:可高效扫描目录,结合定时任务实现监控。
- 部分开源
DirectoryWatcher组件:针对网络路径做了专门优化,稳定性优于原生FileSystemWatcher。
临时修复建议
先给现有代码添加错误事件处理,检查服务运行账户权限,将filesInProgress替换为线程安全集合,验证是否能正常监控UNC路径。若仍无法解决,再切换到定时轮询方案。
内容的提问来源于stack exchange,提问作者Datboydozy
相关产品推荐
相关产品推荐

