定时自动同步文件,支持多文件夹同步,支持过滤文件和文件夹,解决FileSystemWatcher多次文件触发事件(源码)

  博客园里面有很多同步工具和软件,关于FileSystemWatcher类解释的也很多,但收集了很多文章后,感觉没好的方法,自己没事写了一个定时文件同步,借鉴了很多博客园朋友的东西:

上主菜:

  配置文件:

<appSettings>
    <!--原地址(多地址;隔开)-->
    <add key="OldAddress" value="F:akup1;F:akup3"/>
    <!--目标地址-->
    <add key="NewAddress" value="F:akup2"/>
    <!--自动同步时间一般晚上23点开始-->
    <add key="syncTime" value="23"/>
    <!--要过滤的文件夹(多文件名;隔开)-->
    <add key="FiltrationFile" value="Error"/>
    <!--要过滤的文件后缀(多后缀;隔开)-->
    <add key="FiltrationSuffix" value="log"/>
  </appSettings>

  FileSystemWatcher类的Changed事件在每次文件添加和修改的时候,都会触发多次,不晓得微软为什么会有这样的考虑,我看博客园很多人给的解决方案是记录文件写入时间,同一文件写入文件不得小于500ns;

  

lock (dict)
            {
                //过滤文件夹
                if (FiltrationFile(e.FullPath)) return;
                //过滤文件后缀
                if (FiltrationSuffix(e.Name)) return;
                if (dict.ContainsKey(e.FullPath)) 
                {
                    if ((new FileInfo(e.FullPath).LastWriteTime - dict[e.FullPath]).TotalMilliseconds <= 500) //同一文件写入时间不得小于500ns
                        return;
                    else
                        dict.Remove(e.FullPath);
                }
                if (e.ChangeType == WatcherChangeTypes.Changed)
                {
                    if (e.ChangeType == WatcherChangeTypes.Deleted)
                    {
                        return;
                    }
                    //判断文件是否存在.
                    if (System.IO.File.Exists(e.FullPath) == true)
                    {
                        dict.Add(e.FullPath, new FileInfo(e.FullPath).LastWriteTime);
                        Task task = new Task(() =>
                        {
                            FileSave(e.Name, e.FullPath);
                        });
                        task.Start();
                    }
                    System.Threading.Thread.Sleep(1000);
                }
            }

  在同步文件的时候,还有一个问题就是用户文件正在上传,这个触发Change事件都会报错,这个时候需要验证文件是否完整:

  /// <summary>
        /// 判断文件是否完整
        /// </summary>
        /// <param name="path"></param>
        private void Waiting(string path)
        {
            lock (this)
            {
                while (true)
                {
                    try
                    {
                        FileStream stream = File.OpenRead(path);
                        stream.Close();
                        stream.Dispose();
                        return;
                    }
                    catch
                    {

                        System.Threading.Thread.Sleep(5000);
                    }
                }
            }
        }

  在一些项目中,一些日志文件或则一些固定的文件夹是不需要同步的,这都需要验证文件路径是否包含不同的文件夹和文件:

/// <summary>
        /// 过滤文件夹 
        /// </summary>
        private bool FiltrationFile(string fullPath)
        {
            try
            {
                string file = GetAppConfig("FiltrationFile");
                if (string.IsNullOrEmpty(file)) return false;
                file = file.ToLower();
                if (File.Exists(fullPath) == true)
                {
                    string[] items = file.Split(';');
                    List<string> list = fullPath.ToLower().Split('\').ToList();
                    list.RemoveAt(list.Count - 1);
                    for (int i = 0; i < items.Length; i++)
                    {
                        if (list.Count(a => a == items[i]) > 0)
                        {
                            return true;
                        }
                    }
                }
            }
            catch (Exception exp)
            {
                WriteLog(exp.Message);
            }
            return false;
        }

        /// <summary>
        /// 过滤文件名后缀
        /// </summary>
        private bool FiltrationSuffix(string fileName)
        {
            try
            {
                string file = GetAppConfig("FiltrationSuffix");
                if (string.IsNullOrEmpty(file)) return false;
                file = file.ToLower();
                string suffix = fileName.ToLower().Substring(fileName.LastIndexOf('.') + 1);
                string[] items = file.Split(';');
                for (int i = 0; i < items.Length; i++)
                {
                    if (items[i] == suffix)
                    {
                        return true;
                    }
                }
            }
            catch (Exception exp)
            {
                WriteLog(exp.Message);
            }
            return false;
        }

 源码地址:http://files.cnblogs.com/xchit/SyncFile.rar(如果有更好的解决方法可以交流)

原文地址:https://www.cnblogs.com/xchit/p/3455801.html