博客园里面有很多同步工具和软件,关于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; }