文件系统监控的挑战与解决方案

文件系统监控是软件开发中一个常见的需求,尤其是在需要对文件变化做出响应的场景中。.NET框架中的FileSystemWatcher类为此提供了便利,但是它在某些情况下可能会表现出不可预测的行为,例如对单个操作触发多次事件。尽管这不是FileSystemWatcher的缺陷,但确实给开发者带来了额外的挑战。

例如,当一个文件正在被写入时,可能会首先触发一个事件表示文件写入开始,然后再次触发一个事件表示写入结束。虽然这种行为在某些情况下是可预测的,但并不能保证在所有操作系统和应用程序中都能保持一致。

问题示例

考虑一个简单的场景,在Notepad中编辑一个位于c:\temp目录下的文本文件。在这个过程中,FileSystemWatcher可能会触发两次事件。如果能够确信这种行为是一致的,那么可以选择只关注第二次事件。然而,这种假设并不总是安全的。

public class ExampleAttributesChangedFiringTwice { public ExampleAttributesChangedFiringTwice(string demoFolderPath) { var watcher = new FileSystemWatcher() { Path = demoFolderPath, NotifyFilter = NotifyFilters.LastWrite, Filter = "*.txt" }; watcher.Changed += OnChanged; watcher.EnableRaisingEvents = true; } private static void OnChanged(object source, FileSystemEventArgs e) { // 如果在Notepad中编辑文件,这将触发两次 } }

为了解决这个问题,可以采用一种更加稳健的解决方案。

稳健的解决方案

合理使用NotifyFilters可以帮助过滤掉一些不必要的事件,但仍然存在许多场景,即使使用了NotifyFilters,额外的事件仍然会触发。为了解决这个问题,可以使用MemoryCache作为缓冲区来“节流”额外的事件。

当一个文件事件(例如文件更改)被触发时,事件处理程序OnChanged不会立即执行预期的操作,而是将事件存储在MemoryCache中,并设置1秒的过期时间。同时,设置一个CacheItemPolicy回调,在过期时执行。

使用AddOrGetExisting方法可以简单地阻止在缓存期间添加任何额外的事件。

public class BlockAndDelayExample { private readonly MemoryCache _memCache; private readonly CacheItemPolicy _cacheItemPolicy; private const int CacheTimeMilliseconds = 1000; public BlockAndDelayExample(string demoFolderPath) { _memCache = MemoryCache.Default; var watcher = new FileSystemWatcher() { Path = demoFolderPath, NotifyFilter = NotifyFilters.LastWrite, Filter = "*.txt" }; _cacheItemPolicy = new CacheItemPolicy() { RemovedCallback = OnRemovedFromCache }; watcher.Changed += OnChanged; watcher.EnableRaisingEvents = true; } private void OnChanged(object source, FileSystemEventArgs e) { _cacheItemPolicy.AbsoluteExpiration = DateTimeOffset.Now.AddMilliseconds(CacheTimeMilliseconds); _memCache.AddOrGetExisting(e.Name, e, _cacheItemPolicy); } private void OnRemovedFromCache(CacheEntryRemovedArguments args) { if (args.RemovedReason != CacheEntryRemovedReason.Expired) return; var e = (FileSystemEventArgs)args.CacheItem.Value; // 现在实际处理文件事件 } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485