文件监控与处理的高效策略

在开发应用程序时,经常需要监控文件夹以检测新文件的到来,并将这些文件发送到其他地方,甚至可能将其包装成Windows服务。在调试过程中,一切可能都运行得很好。但是,当将其移至测试环境并让手动测试人员开始测试时,他们复制一个文件,文件监控器立即检测到新文件并执行操作,然后突然发生了IOException:因为另一个进程正在使用文件X,导致无法访问。这通常是因为复制操作尚未完成,而事件就已经触发了。即使文件不大,监控器也可能过于高效。

解决方案

当文件系统事件发生时,将其详细信息存储在内存缓存中一段时间。设置一个回调,当事件从内存缓存中过期时执行。在回调中,检查文件是否可用于写操作。如果是,则继续执行预定的文件操作。如果不是,则将其放回内存缓存中一段时间,并重复上述步骤。跟踪并限制获取文件锁定的重试次数是有意义的。

基于之前关于处理多个FileSystemWatcher事件的帖子中的代码构建了这个解决方案。这个示例解决方案的完整代码可以在这里找到。

当处理文件系统事件时,使用一个简单的POCO将文件详细信息和重试计数存储在MemoryCache中,并设置一个计时器,例如60秒:

private void OnCreated(object source, FileSystemEventArgs e) { _cacheItemPolicy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(CacheTimeSeconds); var fileData = new CacheItemValue() { FilePath = e.FullPath, RetryCount = 0, FileName = e.Name }; _memCache.AddOrGetExisting(e.Name, fileData, _cacheItemPolicy); }

一个简单的POCO:

class CacheItemValue { public string FileName { get; set; } public string FilePath { get; set; } public int RetryCount { get; set; } }

在构造函数中,初始化了缓存项策略,当这些缓存的POCOs过期时执行回调

_cacheItemPolicy = new CacheItemPolicy { RemovedCallback = OnRemovedFromCache }; private void OnRemovedFromCache(CacheEntryRemovedArguments args) { // Checking if expired, for a bit of future-proofing if (args.RemovedReason != CacheEntryRemovedReason.Expired) return; var cacheItemValue = (CacheItemValue)args.CacheItem.Value; if (cacheItemValue.RetryCount > MaxRetries) return; if (IsFileLocked(cacheItemValue.FilePath)) { cacheItemValue.RetryCount++; _cacheItemPolicy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(CacheTimeSeconds); _memCache.Add(cacheItemValue.FileName, cacheItemValue, _cacheItemPolicy); } // Now safe to perform the file operation here... }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485