解决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
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
出处:http://jzywh.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。