转:http://www.cnblogs.com/zhaojingjing/archive/2011/01/21/1941586.html
注意:用FileWatcher的Created监控文件时,是指文件刚创建的时候就触发Created(仅仅是出现文件名时),此时的文件还未完成写操作(比如一个图片文件),文件也不是一个完整的文件。用Image.FromFile加载刚刚监听的文件,会报“内存不足”异常。
下面为简单用法:
using System; using System.IO; namespace test { class Program { static void Main(string[] args) { WatcherStrat(@"C:\test", "*.txt"); //由于是控制台程序,加个输入避免主线程执行完毕,看不到监控效果 Console.ReadKey(); } private static void WatcherStrat(string path, string filter) { FileSystemWatcher watcher = new FileSystemWatcher(); watcher.Path = path; watcher.Filter = filter; watcher.Changed += new FileSystemEventHandler(OnProcess); watcher.Created += new FileSystemEventHandler(OnProcess); watcher.Deleted += new FileSystemEventHandler(OnProcess); watcher.Renamed += new RenamedEventHandler(OnRenamed); watcher.EnableRaisingEvents = true; } private static void OnProcess(object source, FileSystemEventArgs e) { if (e.ChangeType == WatcherChangeTypes.Created) { OnCreated(source, e); } else if (e.ChangeType == WatcherChangeTypes.Changed) { OnChanged(source, e); } else if (e.ChangeType == WatcherChangeTypes.Deleted) { OnDeleted(source, e); } } private static void OnCreated(object source, FileSystemEventArgs e) { Console.WriteLine("文件新建事件处理逻辑"); } private static void OnChanged(object source, FileSystemEventArgs e) { Console.WriteLine("文件改变事件处理逻辑"); } private static void OnDeleted(object source, FileSystemEventArgs e) { Console.WriteLine("文件删除事件处理逻辑"); } private static void OnRenamed(object source, RenamedEventArgs e) { Console.WriteLine("文件重命名事件处理逻辑"); } } }
用上面的方法会发现,在一次文本文件变化的时候OnChanged事件会触发两次,这是因为除了文本内容变化之外还有文件其他的属性也变化了例如修改时间。
为了解决这问题,也便于项目当中实际使用,写了下面几个类来实际使用:
using System; using System.IO; namespace test { class Program { static void Main(string[] args) { MyFileSystemWather myWather = new MyFileSystemWather(@"C:\test", "*.txt"); myWather.OnChanged += new FileSystemEventHandler(OnChanged); myWather.OnCreated += new FileSystemEventHandler(OnCreated); myWather.OnRenamed += new RenamedEventHandler(OnRenamed); myWather.OnDeleted += new FileSystemEventHandler(OnDeleted); myWather.Start(); //由于是控制台程序,加个输入避免主线程执行完毕,看不到监控效果 Console.ReadKey(); } private static void OnCreated(object source, FileSystemEventArgs e) { Console.WriteLine("文件新建事件处理逻辑"); } private static void OnChanged(object source, FileSystemEventArgs e) { Console.WriteLine("文件改变事件处理逻辑"); } private static void OnDeleted(object source, FileSystemEventArgs e) { Console.WriteLine("文件删除事件处理逻辑"); } private static void OnRenamed(object source, RenamedEventArgs e) { Console.WriteLine("文件重命名事件处理逻辑"); } } }
WatcherProcess类:
using System.IO; namespace test { public class WatcherProcess { private object sender; private object eParam; public event RenamedEventHandler OnRenamed; public event FileSystemEventHandler OnChanged; public event FileSystemEventHandler OnCreated; public event FileSystemEventHandler OnDeleted; public event Completed OnCompleted; public WatcherProcess(object sender, object eParam) { this.sender = sender; this.eParam = eParam; } public void Process() { if (eParam.GetType() == typeof(RenamedEventArgs)) { OnRenamed(sender, (RenamedEventArgs)eParam); OnCompleted(((RenamedEventArgs)eParam).FullPath); } else { FileSystemEventArgs e = (FileSystemEventArgs)eParam; if (e.ChangeType == WatcherChangeTypes.Created) { OnCreated(sender, e); OnCompleted(e.FullPath); } else if (e.ChangeType == WatcherChangeTypes.Changed) { OnChanged(sender, e); OnCompleted(e.FullPath); } else if (e.ChangeType == WatcherChangeTypes.Deleted) { OnDeleted(sender, e); OnCompleted(e.FullPath); } else { OnCompleted(e.FullPath); } } } } }
MyFileSystemWather类:
using System; using System.Collections; using System.IO; using System.Threading; namespace test { public delegate void Completed(string key); public class MyFileSystemWather { private FileSystemWatcher fsWather; private Hashtable hstbWather; public event RenamedEventHandler OnRenamed; public event FileSystemEventHandler OnChanged; public event FileSystemEventHandler OnCreated; public event FileSystemEventHandler OnDeleted; /// <summary> /// 构造函数 /// </summary> /// <param name="path">要监控的路径</param> public MyFileSystemWather(string path, string filter) { if (!Directory.Exists(path)) { throw new Exception("找不到路径:" + path); } hstbWather = new Hashtable(); fsWather = new FileSystemWatcher(path); // 是否监控子目录 fsWather.IncludeSubdirectories = false; fsWather.Filter = filter; fsWather.Renamed += new RenamedEventHandler(fsWather_Renamed); fsWather.Changed += new FileSystemEventHandler(fsWather_Changed); fsWather.Created += new FileSystemEventHandler(fsWather_Created); fsWather.Deleted += new FileSystemEventHandler(fsWather_Deleted); } /// <summary> /// 开始监控 /// </summary> public void Start() { fsWather.EnableRaisingEvents = true; } /// <summary> /// 停止监控 /// </summary> public void Stop() { fsWather.EnableRaisingEvents = false; } /// <summary> /// filesystemWatcher 本身的事件通知处理过程 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void fsWather_Renamed(object sender, RenamedEventArgs e) { lock (hstbWather) { hstbWather.Add(e.FullPath, e); } WatcherProcess watcherProcess = new WatcherProcess(sender, e); watcherProcess.OnCompleted += new Completed(WatcherProcess_OnCompleted); watcherProcess.OnRenamed += new RenamedEventHandler(WatcherProcess_OnRenamed); Thread thread = new Thread(watcherProcess.Process); thread.Start(); } private void WatcherProcess_OnRenamed(object sender, RenamedEventArgs e) { OnRenamed(sender, e); } private void fsWather_Created(object sender, FileSystemEventArgs e) { lock (hstbWather) { hstbWather.Add(e.FullPath, e); } WatcherProcess watcherProcess = new WatcherProcess(sender, e); watcherProcess.OnCompleted += new Completed(WatcherProcess_OnCompleted); watcherProcess.OnCreated += new FileSystemEventHandler(WatcherProcess_OnCreated); Thread threadDeal = new Thread(watcherProcess.Process); threadDeal.Start(); } private void WatcherProcess_OnCreated(object sender, FileSystemEventArgs e) { OnCreated(sender, e); } private void fsWather_Deleted(object sender, FileSystemEventArgs e) { lock (hstbWather) { hstbWather.Add(e.FullPath, e); } WatcherProcess watcherProcess = new WatcherProcess(sender, e); watcherProcess.OnCompleted += new Completed(WatcherProcess_OnCompleted); watcherProcess.OnDeleted += new FileSystemEventHandler(WatcherProcess_OnDeleted); Thread tdDeal = new Thread(watcherProcess.Process); tdDeal.Start(); } private void WatcherProcess_OnDeleted(object sender, FileSystemEventArgs e) { OnDeleted(sender, e); } private void fsWather_Changed(object sender, FileSystemEventArgs e) { if (e.ChangeType == WatcherChangeTypes.Changed) { if (hstbWather.ContainsKey(e.FullPath)) { WatcherChangeTypes oldType = ((FileSystemEventArgs)hstbWather[e.FullPath]).ChangeType; if (oldType == WatcherChangeTypes.Created || oldType == WatcherChangeTypes.Changed) { return; } } } lock (hstbWather) { hstbWather.Add(e.FullPath, e); } WatcherProcess watcherProcess = new WatcherProcess(sender, e); watcherProcess.OnCompleted += new Completed(WatcherProcess_OnCompleted); watcherProcess.OnChanged += new FileSystemEventHandler(WatcherProcess_OnChanged); Thread thread = new Thread(watcherProcess.Process); thread.Start(); } private void WatcherProcess_OnChanged(object sender, FileSystemEventArgs e) { OnChanged(sender, e); } public void WatcherProcess_OnCompleted(string key) { lock (hstbWather) { hstbWather.Remove(key); } } } }
使用了线程安全的Hashtable来处理一次改变触发两次事件的问题,要注意的是在实际项目使用中,在通过监控文件事情触发时开一个线程WatcherProcess去处理自己业务逻辑的时候,不管业务逻辑成功或者失败(例如有异常抛出一定要try一下)一定要让WatcherProcess的 Completed也就是MyFileSystemWather的WatcherProcess_OnCompleted执行去移除对应变化文件的Hashtable的key,不然下次此文件改变时是无法触发你的业务逻辑的。