如何实时监控文件系统变更并获取未关闭文件的追加内容?
文件系统实时监控未关闭文件追加内容的解决方案
问题背景
我需要开发应用识别文件系统的变更,尤其是文件创建与更新操作。这些文本文件由另一应用创建,该应用完成前不会关闭文件,但我需要获取文件的追加内容。
使用FileSystemWatcher监控时遇到以下问题:
- 若写入文件的应用未关闭文件(且缓冲区未填满),文件内容不会实时更新到磁盘,
FileSystemWatcher无法捕获变更。 - 执行
Write-VolumeCache命令无效,但用记事本打开文件后,FileSystemWatcher能立即收到更新事件——说明存在某种机制可触发写入应用刷新缓冲区。 - 仅知晓文件的部分路径和名称,必须监控指定目录及其子目录,每秒遍历所有文件开销过大。
补充信息:
- PowerShell的
Get-Content -wait <file>可实时显示文件更新内容,同时能触发FileSystemWatcher的事件。 - 尝试过监控文件创建事件后,以流的形式打开文件读取内容,但不知道如何捕获文件关闭事件以释放流资源。
解决方案
1. 记事本触发刷新的核心机制
记事本打开文件时,会以共享读模式(FileShare.ReadWrite)访问文件,Windows文件系统会因此强制写入应用将内核缓冲区中的数据刷新到磁盘——这并非依赖特定命令,而是文件共享访问触发的系统缓存同步机制。你不需要执行外部命令,只需模拟这种共享访问逻辑即可触发刷新。
2. 基于文件流的实时跟踪方案
监控到文件创建事件后,以共享读写模式打开文件流,持续跟踪读取位置,定时读取新增内容:
- 每次读取前记录当前流的
Position,下次读取从该位置开始,避免重复读取旧内容。 - 通过监听
FileSystemWatcher的Deleted事件,或定期检查文件是否存在,来触发流资源的释放。 - 处理文件锁定异常:若写入应用暂时独占文件,捕获异常后重试即可。
示例伪代码:
// 存储正在跟踪的文件流 Dictionary<string, FileStream> trackedStreams = new Dictionary<string, FileStream>(); // 处理文件创建事件 void OnFileCreated(object sender, FileSystemEventArgs e) { try { // 以共享读写模式打开文件,避免阻塞写入应用 var stream = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); trackedStreams.Add(e.FullPath, stream); // 启动后台任务持续读取新增内容 Task.Run(() => ReadStreamContinously(stream, e.FullPath)); } catch (Exception ex) { // 处理文件锁定等异常,可添加重试逻辑 } } async Task ReadStreamContinously(FileStream stream, string filePath) { var reader = new StreamReader(stream); long lastReadPosition = 0; while (trackedStreams.ContainsKey(filePath)) { stream.Position = lastReadPosition; string newContent = await reader.ReadToEndAsync(); if (!string.IsNullOrEmpty(newContent)) { // 处理获取到的新增内容 Console.WriteLine(newContent); lastReadPosition = stream.Position; } await Task.Delay(1000); // 每秒检查一次新增内容 } // 释放资源 reader.Dispose(); stream.Dispose(); } // 处理文件删除事件,释放对应流 void OnFileDeleted(object sender, FileSystemEventArgs e) { if (trackedStreams.ContainsKey(e.FullPath)) { trackedStreams.Remove(e.FullPath); } }
3. 简化方案:借鉴Get-Content -Wait逻辑
Get-Content -Wait的核心逻辑是定期检查文件大小,当文件大小超过上次记录值时,读取新增部分。这种方式不需要维持长连接流,实现更简单,适合对实时性要求不极致的场景:
- 监控到文件创建后,记录初始文件大小。
- 每秒检查一次文件大小,若有增长,读取从上次记录位置到当前文件末尾的内容。
关键注意事项
- 坚持用
FileSystemWatcher监控创建事件,只跟踪已创建的文件,避免全目录遍历的高开销。 - 务必处理资源释放,防止因文件被删除/关闭导致的内存泄漏。
- 针对文件锁定场景,添加重试逻辑,避免单次失败就放弃跟踪。
内容的提问来源于stack exchange,提问作者Anonymous
相关产品推荐
相关产品推荐

