zoukankan      html  css  js  c++  java
  • 使用FileSystemWatcher监视文件更改

        FileSystemWatcher相关介绍请看MSDN(http://msdn.microsoft.com/zh-cn/library/system.io.filesystemwatcher.aspx),本文只是对Changed事件多次触发做一点处理(纯粹个人见解)。

        MSDN对Changed事件的定义为:当对所监视的目录中的文件或目录的大小、系统特性、上次写入时间、上次访问时间或安全权限进行更改时,将引发 Changed 事件。

        首先定义一个基础类型:

        public class FileWatcher
        {
            FileSystemWatcher fsw;
            public event Action<FileSystemEventArgs> OnChange;
    
            public FileWatcher(string path, string filter)
            {
                fsw = new FileSystemWatcher();
                fsw.Path = path;
                fsw.Filter = filter;
                fsw.NotifyFilter = NotifyFilters.LastWrite;
                fsw.Changed += fsw_Changed;
                fsw.EnableRaisingEvents = true;
            }
    
            void fsw_Changed(object sender, FileSystemEventArgs e)
            {
                if (CanRaiseChange(e))
                    RaiseChange(e);
            }
    
            protected virtual bool CanRaiseChange(FileSystemEventArgs e)
            {
                return true;
            }
    
            protected virtual void RaiseChange(FileSystemEventArgs e)
            {
                if (OnChange != null)
                    OnChange.BeginInvoke(e, null, null);//考虑到OnChange执行时间有可能比较长
            }
        }

        因为只需要监视文件内容更改,仅仅监视文件最后写入时间已经足够。在本文之前,找了很多网站,均是以System.Threading.Timer来解决多次触发问题,但由于无法对Timer.Change方法传递额外的参数,在准确性上未免打一些折扣,而且某些解决方案无法处理同一时间修改的多个文件,遂决定自己实现。

        具体思路为:
        1、首先创建一个字典,以文件的完整路径为Key,最后触发Changed时间为Value
        2、对于每个触发的Changed事件,首先判断被修改文件的完整路径是否在字典中,如果不存在则向字典添加
        3、如果存在于字典中,则判断当前被修改文件上一次Changed事件触发的时间与当前触发时间间隔,这里暂且设置为500毫秒
        4、对于500毫秒以内的不作处理
        5、对于超出500毫秒的进行处理,并更新当前被修改文件的Changed事件触发时间

        代码如下:

        public class MyFileWatcher : FileWatcher
        {
            private Dictionary<string, DateTime> changesHistory = new Dictionary<string, DateTime>();
    
            public MyFileWatcher(string path, string filter) :
                base(path, filter) { }
    
            protected override bool CanRaiseChange(FileSystemEventArgs e)
            {
                if (!changesHistory.ContainsKey(e.FullPath))
                {
                    Console.WriteLine("a");
                    changesHistory.Add(e.FullPath, DateTime.Now);
                    return true;
                }
                
                DateTime now = DateTime.Now;
                bool canRaise = (now - changesHistory[e.FullPath]).TotalMilliseconds >= 500;
                if (canRaise)
                    changesHistory[e.FullPath] = now;
                Console.WriteLine(canRaise);
                return canRaise;
            }
        }

        测试代码:

        public static void Main(string[] args)
        {
            MyFileWatcher mfw = new MyFileWatcher("g:\\test\\", "*.txt");
            mfw.OnChange += new Action<FileSystemEventArgs>(fw_OnChange);
            Console.Read();
        }
        
        static void fw_OnChange(FileSystemEventArgs obj)
        {
            Console.WriteLine("{0} {1}", DateTime.Now, obj.FullPath);
        }

        本方法存在一个问题,就是需要监视的文件增多以后,changesHistory字典会不断增大,对性能会有一定影响。可以考虑在CanRaiseChange方法里删除一部分时间间隔比较长的元素。

        另外,对于多线程同时修改一个文件的情况,本方法也无法解决,但已经能满足我的需求。

  • 相关阅读:
    贫血,充血模型的解释以及一些经验(非常经典)(非原创)
    源代码管理安装大全
    20条常见的编码陷阱 你中枪了没?(转)
    从30岁到35岁:为你的生命多积累一些厚度(转)
    Model1 与Model2(转)
    白话MVP(转帖)
    stl string 使用
    TerminateThread不要使用的證據
    C++静态成员函数小结(转)
    C/C++必知必会1
  • 原文地址:https://www.cnblogs.com/lwme/p/1831936.html
Copyright © 2011-2022 走看看