配置文件变更实时监控类(观察者模式)

因为经常要写各种配置文件,所以曾经写过监控文件变更的方法,后来其他地方要用到时每次都要copy不方便,于是修改了下代码,封装成一个类库,这样只要需要监控的文件都可以通过这个类库来实现监控,以下是代码

Observer.cs,文件监控类,利用微软的FileSystemWatcher 实现实时监控,只监控修改

/// <summary>
    /// 文件观察者,只监控文件内容修改,不监控其他诸如文件名称被改,文件被删等
    /// </summary>
    public sealed class Observer
    {
        /// <summary>
        /// 要通知的对象集合
        /// </summary>
        private List<Watcher> _watchers;
        /// <summary>
        /// 文件夹监视者
        /// </summary>
        private FileSystemWatcher _fsw;

        /// <summary>
        /// 当前监控的文件夹完整路径
        /// </summary>
        public string FullPath
        {
            get
            {
                return this._fsw.Path;
            }
        }

        /// <summary>
        /// 文件观察者,只监控文件内容修改,不监控其他诸如文件名称被改,文件被删等
        /// </summary>
        public Observer()
            : this(false)
        {
        }
        public Observer(bool includeSubdirectories)
            : this(AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "Config", "*Config.xml", includeSubdirectories)
        {
        }
        public Observer(string folderPhyPath, string fileFiler)
            : this(folderPhyPath, fileFiler, false)
        { 
        }
        /// <summary>
        /// 文件观察者,只监控文件内容修改,不监控其他诸如文件名称被改,文件被删等
        /// </summary>
        /// <param name="folderPhyPath">要监控的文件夹物理路径,默认为当前该程序的根目录下的Config文件夹</param>
        /// <param name="fileFiler">获取或设置筛选字符串,用于确定在目录中监视哪些文件,默认*Config.xml</param>
        /// <param name="includeSubdirectories">是否监控子文件夹,默认false</param>
        public Observer(string folderPhyPath, string fileFiler, bool includeSubdirectories)
        {
            this._watchers = new List<Watcher>();
            _fsw = new FileSystemWatcher();
            _fsw.Path = folderPhyPath.ToStandardPath();
            _fsw.NotifyFilter = NotifyFilters.LastWrite;
            _fsw.Filter = fileFiler;
            _fsw.Changed += new FileSystemEventHandler(fsw_Changed);
            _fsw.EnableRaisingEvents = true;
            _fsw.IncludeSubdirectories = includeSubdirectories;
        }
        /// <summary>
        /// 当文件夹内监控内容发生变化时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void fsw_Changed(object sender, FileSystemEventArgs e)
        {
            Thread.Sleep(3000);

            IEnumerable<Watcher> watchers = this._watchers.Where(wt => wt.RightPath(e.FullPath));
            if (watchers != null && watchers.Count() > 0)
            {
                foreach (Watcher watcher in watchers)
                {
                    watcher.Notify();
                }
            }
        }
        /// <summary>
        /// 判断文件是否属于当前监控的文件夹
        /// </summary>
        /// <param name="fullFilePath">要判断的文件完整路径</param>
        /// <returns></returns>
        internal bool FilesIn(string fullFilePath)
        {
            FileInfo fi = new FileInfo(fullFilePath);
            bool isIn = false;
            string watchPath = new DirectoryInfo(_fsw.Path).FullName;
            DirectoryInfo di = fi.Directory;
            do
            {
                if (di != null)
                {
                    isIn = di.FullName == watchPath;
                    if (!isIn)
                    {
                        di = di.Parent;
                    }
                }
                else
                {
                    break;
                }
                if (!this._fsw.IncludeSubdirectories)
                {
                    break;
                }
            }
            while (!isIn);
            return isIn;
        }
        /// <summary>
        /// 添加被通知者
        /// </summary>
        /// <param name="afw"></param>
        public void Attach(Watcher wt)
        {
            if (!this._watchers.Contains(wt))
            {
                this._watchers.Add(wt);
            }
        }
        /// <summary>
        /// 移除被通知者
        /// </summary>
        /// <param name="afw"></param>
        public void Detch(Watcher wt)
        {
            this._watchers.Remove(wt);
        }
    }


 

Watcher.cs,通过事件实现配置变更时同步通知,因为FileSystemWatcher的Changed 事件触发时会激发两次,所以利用lastWriteTime来阻止重复变更通知事件,顺便练习了下自定义异常和自定义EventArgs

public delegate void ChangedEventHandler(object sender, FileChangedEventArgs e);
    public class Watcher
    {
        public event ChangedEventHandler Changed;
        /// <summary>
        /// 观察者
        /// </summary>
        private Observer _observer;
        /// <summary>
        /// 文件物理路径
        /// </summary>
        private readonly string _fullPath;
        /// <summary>
        /// Watcher记录到的文件最后修改时间
        /// </summary>
        private DateTime _lastWriteTime;

        public Observer Observer
        {
            get
            {
                return this._observer;
            }
        }

        public Watcher(string fullPath, Observer observer)
        {
            this._fullPath = fullPath.ToStandardPath();
            this._lastWriteTime = File.GetLastWriteTime(this._fullPath);
            if (!observer.FilesIn(this._fullPath))
            {
                throw new FileNotInDirectoryException("指定文件并不存在于指定文件夹内", this._fullPath, observer.FullPath);
            }
            this._observer = observer;
            this.Attach();
        }

        public void Attach()
        {
            this._observer.Attach(this);
        }
        public void Detch()
        {
            this._observer.Detch(this);
        }
        internal void Notify()
        {
            DateTime filesLastWriteTime = File.GetLastWriteTime(this._fullPath);

            if (this._lastWriteTime != filesLastWriteTime)
            {
                this._lastWriteTime = filesLastWriteTime;
                this.OnChange(new FileChangedEventArgs(this._fullPath));
            }
        }
        protected virtual void OnChange(FileChangedEventArgs e)
        {
            if (Changed != null)
            {
                Changed(this, e);
            }
        }

        internal bool RightPath(string fullPath)
        {
            return this._fullPath == fullPath;
        }
    }
    /// <summary>
    /// 包含变化文件相关的数据
    /// </summary>
    [Serializable]
    [System.Runtime.InteropServices.ComVisible(true)]
    public class FileChangedEventArgs : EventArgs
    {
        private readonly string _fullPath;
        public FileChangedEventArgs(string fullPath)
        {
            this._fullPath = fullPath.ToStandardPath();
        }
        public string FullPath
        {
            get
            {
                return this._fullPath;
            }
        }
    }
    /// <summary>
    /// 当指定文件不存在于指定文件夹内时引发异常
    /// </summary>
    [Serializable]
    [System.Runtime.InteropServices.ComVisible(true)]
    public class FileNotInDirectoryException : IOException
    {
        private readonly string _fileName, _directoryName;

        public FileNotInDirectoryException()
            : base("File Not In Directory")
        {
        }

        public FileNotInDirectoryException(string message)
            : base(message)
        {
        }
        public FileNotInDirectoryException(string message, Exception innerException)
            : base(message, innerException)
        {
        }
        //
        // 摘要:
        //     使用指定错误信息和对作为此异常原因的内部异常的引用来初始化 System.IO.FileNotFoundException 类的新实例。
        //
        // 参数:
        //   message:
        //     解释异常原因的错误信息。
        //
        //   fileName:
        //     一个 System.String,它包含要验证的文件的完整路径
        //
        //   directoryName
        //     一个 System.String,它包含要验证的文件夹的完整路径
        //
        //   innerException:
        //     导致当前异常的异常。如果 innerException 参数不为 null,则当前异常在处理内部异常的 catch 块中引发。
        public FileNotInDirectoryException(string message, string fileName, string directoryName)
            : base(message)
        {
            this._fileName = fileName;
            this._directoryName = directoryName;
        }
        //
        // 摘要:
        //     用指定的序列化和上下文信息初始化 System.IO.IOException 类的新实例。
        //
        // 参数:
        //   info:
        //     用于序列化或反序列化对象的数据。
        //
        //   context:
        //     对象的源和目标。
        protected FileNotInDirectoryException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
            : base(info, context)
        {
        }


        public FileNotInDirectoryException(string message, string fileName, string directoryName, Exception innerException)
            : base(message, innerException)
        {
            this._fileName = fileName;
            this._directoryName = directoryName;
        }

        public string FileName
        {
            get
            {
                return this._fileName;
            }
        }
        public string DirectoryName
        {
            get
            {
                return this._directoryName;
            }
        }

        public override string ToString()
        {
            return "File:" + this._fileName + Environment.NewLine +
                "Directory:" + this._directoryName + Environment.NewLine +
                base.ToString();
        }
    }

    internal static class FullPathHelper
    {
        public static string ToStandardPath(this string fullPath)
        {
            return fullPath.Replace('/', '\\');
        }
    }


使用代码

public class Demo
    {
        private Watcher _watcher;
        private Observer _observer;
        
        public Demo()
        {
            this._observer = new Observer();
            string fullPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "Config\\SSOConfig.xml";
            this._watcher = new Watcher(fullPath, this._observer);
            this._watcher.Changed += new ChangedEventHandler(_watcher_Changed);

            this.InitParameters(fullPath);
        }

        private void _watcher_Changed(object sender, FileChangedEventArgs e)
        {
            this.InitParameters(e.FullPath);
        }

        private void InitParameters(string fullPath)
        {
        }
}


 

有些代码还是写的不好,有点重复的感觉,没有定义接口或抽象,因为我只针对文件变更监控,没有预见可能会变更的地方,如果要实现监控其他的变更的话,可以修改相应的监控代码,只要是FileSystemWatcher能监控的 :P

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值