1. 程式人生 > >偵聽Windows資料夾變更事件

偵聽Windows資料夾變更事件

通過以下兩個類,可以實現對windows資料夾的事件偵聽,包括新建檔案,刪除檔案,檔案重新命名等事件;

FileSystemWather.cs

using System;
using System.Collections;
using System.IO;
using System.Threading;

namespace Whir.Software.FileCopy
{
    public delegate void Completed(string key);

    public class FileSystemWather
    {
        private readonly FileSystemWatcher _fsWather;

        private readonly Hashtable _hstbWather;

        /// <summary>
        ///     建構函式
        /// </summary>
        /// <param name="path">要監控的路徑</param>
        /// <param name="filter">要監控的檔案</param>
        /// <param name="includeSubdirectories">是否包含子資料夾</param>
        public FileSystemWather(string path, string filter, bool includeSubdirectories)
        {
            if (!Directory.Exists(path))
            {
                throw new Exception("找不到路徑:" + path);
            }

            _hstbWather = new Hashtable();

            _fsWather = new FileSystemWatcher(path) {IncludeSubdirectories = includeSubdirectories, Filter = filter};
            _fsWather.Renamed += fsWather_Renamed;
            _fsWather.Changed += fsWather_Changed;
            _fsWather.Created += fsWather_Created;
            _fsWather.Deleted += fsWather_Deleted;
        }

        public event RenamedEventHandler OnRenamed;
        public event FileSystemEventHandler OnChanged;
        public event FileSystemEventHandler OnCreated;
        public event FileSystemEventHandler OnDeleted;

        /// <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)
            {
                if (!_hstbWather.ContainsKey(e.FullPath))
                {
                    _hstbWather.Add(e.FullPath, e);
                }
            }
            var watcherProcess = new WatcherProcess(sender, e);
            watcherProcess.OnRenamed += OnRenamed; //傳遞事件
            watcherProcess.OnCompleted += WatcherProcess_OnCompleted;
            var thread = new Thread(watcherProcess.Process);
            thread.Start();
        }


        private void fsWather_Created(object sender, FileSystemEventArgs e)
        {
            lock (_hstbWather)
            {
                if (!_hstbWather.ContainsKey(e.FullPath))
                {
                    _hstbWather.Add(e.FullPath, e);
                }
            }
            var watcherProcess = new WatcherProcess(sender, e);
            watcherProcess.OnCreated += OnCreated; //傳遞事件
            watcherProcess.OnCompleted += WatcherProcess_OnCompleted;
            var threadDeal = new Thread(watcherProcess.Process);
            threadDeal.Start();
        }

        private void fsWather_Deleted(object sender, FileSystemEventArgs e)
        {
            lock (_hstbWather)
            {
                if (!_hstbWather.ContainsKey(e.FullPath))
                {
                    _hstbWather.Add(e.FullPath, e);
                }
            }
            var watcherProcess = new WatcherProcess(sender, e);
            watcherProcess.OnDeleted += OnDeleted; //傳遞事件
            watcherProcess.OnCompleted += WatcherProcess_OnCompleted;
            var tdDeal = new Thread(watcherProcess.Process);
            tdDeal.Start();
        }

        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)
            {
                if (!_hstbWather.ContainsKey(e.FullPath))
                {
                    _hstbWather.Add(e.FullPath, e);
                }
            }
            var watcherProcess = new WatcherProcess(sender, e);
            watcherProcess.OnChanged += OnChanged; //傳遞事件
            watcherProcess.OnCompleted += WatcherProcess_OnCompleted;
            var thread = new Thread(watcherProcess.Process);
            thread.Start();
        }

        /// <summary>
        ///     使用了執行緒安全的Hashtable來處理一次改變觸發兩次事件的問題,
        ///     要注意的是在實際專案使用中,在通過監控檔案事情觸發時開一個執行緒WatcherProcess去處理自己業務邏輯的時候,
        ///     不管業務邏輯成功或者失敗(例如有異常丟擲一定要try一下)一定要讓WatcherProcess的Completed
        ///     也就是MyFileSystemWather的WatcherProcess_OnCompleted執行去移除對應變化檔案的Hashtable的key,
        ///     不然下次此檔案改變時是無法觸發你的業務邏輯的。
        /// </summary>
        /// <param name="key"></param>
        public void WatcherProcess_OnCompleted(string key)
        {
            lock (_hstbWather)
            {
                _hstbWather.Remove(key);
            }
        }
    }
}
WatcherProcess.cs
using System.IO;

namespace Whir.Software.FileCopy
{
    public class WatcherProcess
    {
        private readonly object _eParam;
        private readonly object _sender;

        public WatcherProcess(object sender, object eParam)
        {
            _sender = sender;
            _eParam = eParam;
        }

        public event RenamedEventHandler OnRenamed;
        public event FileSystemEventHandler OnChanged;
        public event FileSystemEventHandler OnCreated;
        public event FileSystemEventHandler OnDeleted;
        public event Completed OnCompleted;

        public void Process()
        {
            if (_eParam.GetType() == typeof (RenamedEventArgs))
            {
                OnRenamed(_sender, (RenamedEventArgs) _eParam);
                OnCompleted(((RenamedEventArgs) _eParam).FullPath);
            }
            else
            {
                var 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);
                }
            }
        }
    }
}
使用方法:
var wather = new FileSystemWather(TxtFrom.Text, "*.*", true);
            wather.OnChanged += OnChanged;
            wather.OnCreated += OnCreated;
            wather.OnRenamed += OnRenamed;
            wather.OnDeleted += OnDeleted;
            wather.Start();
對應事件響應:
        private void OnCreated(object source, FileSystemEventArgs e)
        {
            //檔案全路徑:e.FullPath
            //檔名:e.Name
            //事件型別: e.ChangeType
            //自定義邏輯處理
        }
        private void OnChanged(object source, FileSystemEventArgs e)
        {
            //自定義邏輯處理
        }
        private void OnDeleted(object source, FileSystemEventArgs e)
        {
            //自定義邏輯處理
        }
        private void OnRenamed(object source, RenamedEventArgs e)
        {
            //自定義邏輯處理
        }