解决FileSystemWatcher事件多次触发的方法

 

博客园已有几位同学发表了关于FileSystemWatcher事件多次触发的解决方法的文章,很好地解决了事件多次激发的问题。

主要方法有:

1.延迟激发法。

http://www.cnblogs.com/dragon/archive/2008/07/04/filesystemwatcher.html

原理是延迟调用事件的代理,将多次事件合并为一次,从而很好的解决了此问题,唯一的缺憾是时间激发不及时,不适用于实时性较高的系统。




2.临时禁用法。

 

 1: void watcher_Changed(object sender, FileSystemEventArgs e) 
 2: { 
 3: if (watcher != null) 
 4: { 
 5: //解决执行两次的问题 
 6: watcher.EnableRaisingEvents = false; 
 7: Thread th = new Thread(new ThreadStart( 
 8: delegate() 
 9: { 
 10: Thread.Sleep(1000); 
 11: watcher.EnableRaisingEvents = true; 
 12: } 
 13: )); 
 14: th.Start(); 
 15: } 
 16: } 

这种方法是监视单个文件的情况下的最简单解决办法。但是很明显,在监视多个文件的情况下就有很大的问题,文件的事件很可能丢失,在高并发的情况下很容易出问题。


 

我这里要提出的新的方法叫“检查最后更新时间法”,原理是在FileSystemWatcher事件激发时先检查更新的文件的最后更新时间是否已经被记录, 如果未被记录则激发event,否则不激发。

具体代码如下

 1: using System;
 2: using System.Collections.Generic;
 3: using System.Linq;
 4: using System.Text;
 5: using System.IO;
 6:  
 7: namespace GiantSoft.Common
 8: {
 9: public class GiantFileSystemWatcher : IDisposable
 10: {
 11: private FileSystemWatcher m_Watcher;
 12:  
 13: private Dictionary<string, DateTime> m_DictUpdateTime = new Dictionary<string, DateTime>();
 14:  
 15: public GiantFileSystemWatcher(string path, string filter)
 16: {
 17: m_Watcher = new FileSystemWatcher(path, filter);
 18: m_Watcher.Error += new ErrorEventHandler(m_Watcher_Error);
 19: m_Watcher.EnableRaisingEvents = false;
 20: m_Watcher.IncludeSubdirectories = true;
 21: }
 22:  
 23: void m_Watcher_Error(object sender, ErrorEventArgs e)
 24: {
 25: LogUtil.LogError(e.GetException());
 26: }
 27:  
 28: public bool Start()
 29: {
 30: if (m_FileChangeHandler != null)
 31: {
 32: m_Watcher.Changed += new FileSystemEventHandler(m_Watcher_Changed);
 33: m_Watcher.Created += new FileSystemEventHandler(m_Watcher_Changed);
 34: m_Watcher.Renamed += new RenamedEventHandler(m_Watcher_Changed);
 35: m_Watcher.EnableRaisingEvents = true;
 36: return true;
 37: }
 38: else
 39: {
 40: return false;
 41: }
 42: }
 43:  
 44: void m_Watcher_Changed(object sender, FileSystemEventArgs e)
 45: {
 46: try
 47: {
 48: DateTime lastModifyTime = File.GetLastWriteTime(e.FullPath);
 49: DateTime prevModifyTime = DateTime.MinValue;
 50:  
 51: if (m_DictUpdateTime.TryGetValue(e.FullPath.ToLower(), out prevModifyTime))
 52: {
 53: if (lastModifyTime <= prevModifyTime)
 54: {
 55: return;
 56: }
 57: else
 58: {
 59: m_DictUpdateTime[e.FullPath.ToLower()] = lastModifyTime;
 60: }
 61: }
 62: else
 63: {
 64: m_DictUpdateTime[e.FullPath.ToLower()] = lastModifyTime;
 65: }
 66:  
 67: if (m_FileChangeHandler != null)
 68: {
 69: m_FileChangeHandler.Invoke(this, e);
 70: }
 71: }
 72: catch (Exception exc)
 73: {
 74: LogUtil.LogError(exc);
 75: }
 76: }
 77:  
 78: private FileSystemEventHandler m_FileChangeHandler;
 79:  
 80: public event FileSystemEventHandler FileChangeHandler
 81: {
 82: add { m_FileChangeHandler += value; }
 83: remove { m_FileChangeHandler -= value; }
 84: }
 85:  
 86: #region IDisposable Members
 87:  
 88: public void Dispose()
 89: {
 90: m_DictUpdateTime.Clear();
 91: m_DictUpdateTime = null;
 92: m_Watcher.EnableRaisingEvents = false;
 93: if (m_FileChangeHandler != null)
 94: {
 95: m_Watcher.Changed -= new FileSystemEventHandler(m_Watcher_Changed);
 96: m_Watcher.Created -= new FileSystemEventHandler(m_Watcher_Changed);
 97: m_Watcher.Renamed -= new RenamedEventHandler(m_Watcher_Changed);
 98: }
 99: m_Watcher.Dispose();
 100: }
 101:  
 102: #endregion
 103: }
 104: }

 

 

 

这种解决方法能够满足绝大部分的需求,但是对于监视数量巨大的文件会有性能问题,Dictionary的性能会随着文件数量的增加而降低。


作者:江大鱼
出处:http://jzywh.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
posted @ 2008-07-23 21:55  江大渔  阅读(8633)  评论(6编辑  收藏  举报