
FileSystemWatcher 能不能直接监视 UNC 路径?
能,但有严格前提:UNC 路径必须可被 Windows 作为本地文件系统路径访问,且 FileSystemWatcher 实例需以支持网络重定向的权限运行。常见失败不是因为“不支持 UNC”,而是路径未被正确解析或权限/网络层阻断。
为什么监视 \servershare 总是触发一次就停止?
这是最典型的 UNC 监控失效现象,根本原因通常是:FileSystemWatcher 的底层依赖于 Windows 目录变更通知(ReadDirectoryChangesW),而该 API 在 UNC 路径上对 SMB 会话中断、凭据过期、服务器端缓存策略(如 SMB signing 或 oplock 行为)极其敏感。
- 确保 UNC 路径已手动访问过(例如在资源管理器中打开过
\servershare),触发系统建立并缓存有效的 SMB 会话 - 避免使用已注销的用户上下文启动监听(如 Windows 服务默认以 LocalSystem 运行,无法继承用户凭据;应改用特定域账户或启用
LoadUserProfile) - 设置
EnableRaisingEvents = true后,立刻检查IncludeSubdirectories和NotifyFilter是否合理——例如只监听NotifyFilters.FileName却收到大量属性变更,可能被静默丢弃 - 务必订阅
Error事件,并在回调中检查EventArgs.GetException(),常见错误包括"The network path was not found"或"Access is denied"
替代方案:当 FileSystemWatcher 持续掉线时怎么办?
不要硬扛——UNC 环境下 FileSystemWatcher 本质是“尽力而为”,稳定监控需降级为轮询 + 状态比对。关键不是重写逻辑,而是控制开销和精度:
- 用
Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)获取快照,配合FileInfo.LastWriteTimeUtc和FileInfo.Length做轻量哈希(避免全文件 MD5) - 轮询间隔建议 ≥ 30 秒;若需近实时,可先用
FileSystemWatcher做“唤醒信号”,再触发一次精准比对 - 注意 SMB 服务器端的
IRPStackSize或DirectoryCacheLifetime注册表设置,它们会影响GetFiles返回时效性 - 若共享启用了 VSS 或卷影副本,
FileSystemWatcher可能完全收不到事件——此时轮询是唯一可靠方式
一个最小可行监控示例(含错误兜底)
以下代码不是“完美解”,而是暴露关键控制点:
var watcher = new FileSystemWatcher(@"\fileserverdocs") {
IncludeSubdirectories = true,
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime,
EnableRaisingEvents = false // 先不启动
};
watcher.Changed += (s, e) => Console.WriteLine($"Changed: {e.FullPath}");
watcher.Error += (s, e) => {
Console.WriteLine($"Watcher error: {e.GetException()?.Message}");
// 这里应触发自动重建 watcher 实例(重新 new + 重新 EnableRaisingEvents)
};
// 确保路径可达后再启用
if (Directory.Exists(watcher.Path)) {
watcher.EnableRaisingEvents = true;
} else {
Console.WriteLine("UNC path not accessible — check credentials and SMB session");
}
真正难的从来不是写几行监听代码,而是判断当前 UNC 路径所处的 SMB 协议版本、服务器安全策略、以及客户端网络栈是否允许持续挂起句柄——这些信息不会出现在异常堆栈里,得去 eventvwr.msc 看“Microsoft-Windows-SMBClient/Connectivity” 日志。








