您的位置:首页 > 编程语言 > C#

本地文件同步——C#源代码

2017-06-12 14:41 183 查看
作者:Ron Ngai

出处:http://www.cnblogs.com/rond

本地文件同步——C#源代码

入职之后接到的第一个代码任务是一个小测试。做一个文件单向同步软件。

需求描述:

将文件夹A内的文件夹和文件同步到文件夹B。
其实需求也就那么一句话,没啥还需要解释的了吧。详细点说,需要同步文件/文件夹的“新增,删除,重命名,修改”。
一开始我的想法是先Google,然后在博客园找到这篇文章《C#文件同步工具教程》。这篇文章的核心来自msdn里面FileSystemWatcher
的解释。就是用对象FileSystemWatcher 去监听文件是否被创建,重命名,删除,修改。如果发生了就调用相对应的事件,将被修改,创建,重命名的文件复制到目标目录B当中。这个例子比较简单,很多事情都没考虑到。而且我认为用FileSystemWatcher 去监听所有的文件,太浪费CPU和内存。

我的想法

是采用递归,遍历整个源目录,对比目标目录。

如果目标目录下没有相对应的文件,将文件复制到目标目录;
如果文件在两个路径下都存在,但是文件大小和最后写入时间不一致时,将原目录下的文件复制到目标目录下;
如果文件存在于目标目录下而不存在源目录下,则将目标路径下的文件删除。

实现

知道如何比较之后就可以进行递归遍历文件夹了。这个是这个软件实现的难点之一,其实也没多难,也就是说这个软件根本就没多难。以下是递归函数:





1 /// <summary>
2 /// 递归核心 同步目录
3 /// </summary>
4 /// <param name="src">原路径</param>
5 /// <param name="obj">目标路径</param>
6 static void loop(string src, string obj)    // 递归核心 同步目录
7 {
8     CopyFistly(src, obj);   //先同步文件
9
10     //遍历文件夹,递归调用
11     DirectoryInfo dirSrc = new DirectoryInfo(src);
12     DirectoryInfo[] dirs = dirSrc.GetDirectories();
13     foreach (DirectoryInfo dir in dirs)
14     {
15         string str = dir.Name;
16         if (Directory.Exists(obj + "\\" + dir.Name) == false)
17         {
18             str = Directory.CreateDirectory(obj + "\\" + dir.Name).ToString();
19         }
20         //注意这里,这里是递归,而且是下面要注意的地方
21         loop(src + "\\" + dir.ToString(), obj + "\\" + str);
22     }
23 }






测试了一下结果,在9000+个文件,40+个文件夹下,在我这部破机器上面单纯递归遍历(不复制文件)的时候需要的时间是截枝的十倍以上。简直是只乌龟。。。



优化

所以要想办法缩短时间提高效率。既然复制文件上面我们无法操作,那我们只好在递归上面进行优化。上个星期我发了一篇文章叫做《算法——回溯法》。这个时候刚好可以用上这种方法了。因为本身用的就是递归,而且文件夹的结构本身就是一个树的结构,在恰好满足了回溯法的要求。在遍历上面,并不需要在所有的文件夹都遍历一遍。因为有些文件夹并没有发生改变,所有就没有必要遍历下去了。所以就需要在递归调用自己之前先加一个条件,也就是加上约束函数。修改之后,代码如下:





1 /// <summary>
2 /// 递归核心 同步目录
3 /// </summary>
4 /// <param name="src">原路径</param>
5 /// <param name="obj">目标路径</param>
6 static void loop(string src, string obj)    // 递归核心 同步目录
7 {
8     CopyFistly(src, obj);   //先同步文件
9
10     //遍历文件夹,递归调用
11     DirectoryInfo dirSrc = new DirectoryInfo(src);
12     DirectoryInfo[] dirs = dirSrc.GetDirectories();
13     foreach (DirectoryInfo dir in dirs)
14     {
15         string str = dir.Name;
16         if (Directory.Exists(obj + "\\" + dir.Name) == false)
17         {
18             str = Directory.CreateDirectory(obj + "\\" + dir.Name).ToString();
19         }
20         DirectoryInfo dirObj = new DirectoryInfo(str);
21         //约束函数 在大小不一致的时候进行同步,其他状态不同步
22         if (GetDirectoryLength(src + "\\" + dir.ToString()) != GetDirectoryLength(obj + "\\" + str))
23             loop(src + "\\" + dir.ToString(), obj + "\\" + str);
24     }
25 }






函数GetDirectoryLength(string path)的作用是检查文件夹path的大小。这里只是简单地对比两个文件夹的大小,如果大小一致,则截枝不递归,否则递归。这种方式的效率非常高,因为很多时候并不是都在有文件的复制,所以不需要经常去遍历目录。所以截枝就好了。下面给出GetDirectoryLength(string path)函数的代码。其实该函数也是一个递归,虽然会增加负荷,但是文件多,文件夹深的时候,是很有必要的。







获取文件夹大小



1 /// <summary>
2 /// 获取路径下文件夹的大小
3 /// </summary>
4 /// <param name="dirPath">目标路径</param>
5 /// <returns>文件夹大小</returns>
6 public static long GetDirectoryLength(string dirPath)
7 {
8     //判断给定的路径是否存在,如果不存在则退出
9     if (!Directory.Exists(dirPath))
10         return 0;
11     long len = 0;
12
13     //定义一个DirectoryInfo对象
14     DirectoryInfo di = new DirectoryInfo(dirPath);
15
16     //通过GetFiles方法,获取di目录中的所有文件的大小
17     foreach (FileInfo fi in di.GetFiles())
18     {
19         len += fi.Length;
20     }
21
22     //获取di中所有的文件夹,并存到一个新的对象数组中,以进行递归
23     DirectoryInfo[] dis = di.GetDirectories();
24     if (dis.Length > 0)
25     {
26         for (int i = 0; i < dis.Length; i++)
27         {
28             len += GetDirectoryLength(dis[i].FullName);
29         }
30     }
31     return len;
32 }







难点主要在递归和截枝的思想上面。其他方面的解释可以直接查看代码。注释已经很清楚了。下面是整个文件的源代码:







文件同步



1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.IO;
6 using System.Threading;
7 using System.Configuration;
8
9 namespace FileSynLoop
10 {
11     class Program
12     {
13         static private string strSource = GetAppConfig("src");   //原路径
14         static private string strObjective = GetAppConfig("obj");    //目标路径
15         static private int synTime = 0;  //同步时间
16         static private string flag = ""; //多线程控制标志 同步控制
17         static private Thread threadShow;   //显示效果线程
18         static private bool bound;  //是否使用截枝函数
19
20         static void Main(string[] args)
21         {
22             //基本设置
23             Console.WriteLine("原路径:" + strSource);
24             Console.WriteLine("目标路径:" + strObjective);
25             try { synTime = Convert.ToInt32(GetAppConfig("synTime")); }
26             catch (Exception e) { Console.WriteLine("配置的同步时间格式不正确:" + e.Message); return; }
27             Console.WriteLine("同步间隔时间:" + synTime + "毫秒");
28
29             if (Directory.Exists(strSource) == false){Console.WriteLine("配置的原路径不存在");return;}
30             if (Directory.Exists(strObjective) == false){Console.WriteLine("配置的目标路径不存在"); return;}
31
32             Console.WriteLine("是否使用截枝函数?使用截止函数无法同步空文件夹/空文件。默认使用截枝!y/n");
33             if (Console.ReadLine() == "n")
34                 bound = false;
35             else
36                 bound = true;
37
38             do{Console.WriteLine("输入ok开始!");}
39             while (Console.ReadLine() != "ok");
40
41             //线程
42             Thread thread = new Thread(new ThreadStart(ThreadProc));
43             threadShow = new Thread(new ThreadStart(ThreadShow));
44             thread.Start();
45             threadShow.Start(); //开始线程
46             threadShow.Suspend();   //挂起线程
47             //退出
48             while ((flag = Console.ReadLine()) != "exit") ;
49         }
50
51         //线程控制
52         public static void ThreadProc()
53         {
54             int i = 0;
55             DateTime dt;
56             TimeSpan ts;
57
58             while (flag != "exit")
59             {
60                 dt = DateTime.Now;
61                 Console.WriteLine();
62                 Console.Write("第" + ++i + "次同步开始:");
63                 threadShow.Resume();    //恢复线程
64                 try
65                 {
66                     loop(strSource, strObjective);
67                 }
68                 catch (Exception e)
69                 {
70                     Console.WriteLine("文件夹“" + strSource + "“被占用,暂时无法同步!8:" + e.Message);
71                 }
72                 threadShow.Suspend();   //挂起线程
73
74                 ts = DateTime.Now - dt;
75                 Console.WriteLine("|");
76                 if (GetDirectoryLength(strSource) == GetDirectoryLength(strObjective))
77                     Console.WriteLine("所有同步完毕!");
78                 Console.WriteLine("第" + i + "次同步结束,耗时"+ts.ToString()+",正在等待下次开始!");
79                 Thread.Sleep(synTime);//同步时间
80             }
81         }
82
83         //显示效果的线程
84         public static void ThreadShow()
85         {
86             while (flag != "exit")
87             {
88                 Console.Write(">");
89                 Thread.Sleep(500);
90             }
91         }
92
93         /// <summary>
94         /// 递归核心 同步目录
95         /// </summary>
96         /// <param name="src">原路径</param>
97         /// <param name="obj">目标路径</param>
98         static void loop(string src, string obj)    // 递归核心 同步目录
99         {
100             CopyFistly(src, obj);   //先同步文件
101
102             //遍历文件夹,递归调用
103             DirectoryInfo dirSrc = new DirectoryInfo(src);
104             DirectoryInfo[] dirs = dirSrc.GetDirectories();
105             foreach (DirectoryInfo dir in dirs)
106             {
107                 string str = dir.Name;
108                 if (Directory.Exists(obj + "\\" + dir.Name) == false)
109                 {
110                     str = Directory.CreateDirectory(obj + "\\" + dir.Name).ToString();
111                 }
112                 DirectoryInfo dirObj = new DirectoryInfo(str);
113                 if (bound)
114                 {
115                     //约束函数 在大小不一致的时候进行同步,其他状态不同步
116                     if (GetDirectoryLength(src + "\\" + dir.ToString()) != GetDirectoryLength(obj + "\\" + str))
117                         loop(src + "\\" + dir.ToString(), obj + "\\" + str);
118                 }
119                 else
120                 {
121                     loop(src + "\\" + dir.ToString(), obj + "\\" + str);
122                 }
123             }
124         }
125
126         /// <summary>
127         /// 同步文件
128         /// </summary>
129         /// <param name="strSource">源目录</param>
130         /// <param name="strObjective">目标目录</param>
131         static private void CopyFistly(string strSource, string strObjective)   //同步文件
132         {
133             string[] srcFileNames = Directory.GetFiles(strSource).Select(s => System.IO.Path.GetFileName(s)).ToArray(); //原路径下的所有文件
134             string[] objFileNames = Directory.GetFiles(strObjective).Select(s => System.IO.Path.GetFileName(s)).ToArray();  //目标路径下的所有文件
135
136             #region 同步新建 修改
137             foreach (string strSrc in srcFileNames) //遍历源文件夹
138             {
139                 FileInfo aFile = new FileInfo(strSource + "\\" + strSrc);
140                 string aAccessTime = aFile.LastWriteTime.ToString();
141                 string aCreateTime = aFile.CreationTime.ToString();
142
143
144                 string bCreateTime = "";    //目标路径文件的信息
145                 string bAccessTime = "";
146
147                 bool flag = false;
148                 foreach (string strObj in objFileNames) //遍历目标文件夹
149                 {
150                     FileInfo bFile = new FileInfo(strObjective + "\\" + strObj);
151                     bAccessTime = bFile.LastWriteTime.ToString();
152                     bCreateTime = bFile.CreationTime.ToString();
153
154                     if (strSrc == strObj)   //文件存在目标路径当中
155                     {
156                         if (aCreateTime != bCreateTime || aAccessTime != bAccessTime)   //文件存在但是不一致
157                         {
158                             try
159                             {
160                                 File.Copy(strSource + "\\" + strSrc, strObjective + "\\" + strSrc, true);
161                                 FileInfo file = new FileInfo(strObjective + "\\" + strSrc);
162                                 file.CreationTime = Convert.ToDateTime(aCreateTime);
163                                 file.LastAccessTime = Convert.ToDateTime(aAccessTime);
164                             }
165                             catch (Exception e)
166                             {
167                                 Console.WriteLine("文件“" + strSrc + "“被占用,暂时无法同步!4:" + e.Message);
168                             }
169                         }
170                         flag = true;
171                         break;
172                     }
173                 }
174
175                 if (flag == false)  //文件不存在目标路径当中
176                 {
177                     try
178                     {
179                         File.Copy(strSource + "\\" + strSrc, strObjective + "\\" + strSrc, true);
180                         FileInfo file = new FileInfo(strObjective + "\\" + strSrc);
181                         file.CreationTime = Convert.ToDateTime(aCreateTime);
182                         file.LastAccessTime = Convert.ToDateTime(aAccessTime);
183                     }
184                     catch (Exception e)
185                     {
186                         Console.WriteLine("文件“" + strSrc + "“被占用,暂时无法同步!5" + e.Message);
187                     }
188                 }
189             }
190             #endregion
191
192             #region 同步删除 重命名
193             //删除文件
194             foreach (string strObj in objFileNames) //遍历目标文件夹
195             {
196                 string allObj = strObjective + "\\" + strObj;
197                 bool flag = false;
198                 foreach (string strSrc in srcFileNames) //遍历源文件夹
199                 {
200                     if (strObj == strSrc)
201                         flag = true;
202                 }
203                 if (flag == false)
204                 {
205                     try
206                     {
207                         File.Delete(allObj);
208                     }
209                     catch (Exception e)
210                     {
211                         Console.WriteLine("文件“" + strObj + "“被占用,暂时无法同步!6" + e.Message);
212                     }
213                 }
214             }
215
216             //删除文件夹
217             DirectoryInfo dirSrc = new DirectoryInfo(strSource);
218             DirectoryInfo[] dirsSrc = dirSrc.GetDirectories();
219             DirectoryInfo dirObj = new DirectoryInfo(strObjective);
220             DirectoryInfo[] dirsObj = dirObj.GetDirectories();
221             foreach (DirectoryInfo bdirObj in dirsObj)
222             {
223                 bool flag = false;
224                 foreach (DirectoryInfo adirSrc in dirsSrc)
225                 {
226                     if (bdirObj.Name == adirSrc.Name)
227                     {
228                         flag = true;
229                     }
230                 }
231                 if (flag == false)  //如果文件夹只出现在目的路径下而不再源目录下,删除该文件夹
232                 {
233                     try
234                     {
235                         Directory.Delete(dirObj + "\\" + bdirObj, true);
236                     }
237                     catch (Exception e)
238                     {
239                         Console.WriteLine("文件夹“" + bdirObj + "“被占用,暂时无法同步!8" + e.Message);
240                     }
241                 }
242             }
243             #endregion
244
245         }
246
247         /// <summary>
248         /// 获取自定义配置的值
249         /// </summary>
250         /// <param name="strKey">键值</param>
251         /// <returns>键值对应的值</returns>
252         private static string GetAppConfig(string strKey)
253         {
254             foreach (string key in ConfigurationManager.AppSettings)
255             {
256                 if (key == strKey)
257                 {
258                     return ConfigurationManager.AppSettings[strKey];
259                 }
260             }
261             return null;
262         }
263
264         /// <summary>
265         /// 获取路径下文件夹的大小
266         /// </summary>
267         /// <param name="dirPath">目标路径</param>
268         /// <returns>文件夹大小</returns>
269         public static long GetDirectoryLength(string dirPath)
270         {
271             //判断给定的路径是否存在,如果不存在则退出
272             if (!Directory.Exists(dirPath))
273                 return 0;
274             long len = 0;
275
276             //定义一个DirectoryInfo对象
277             DirectoryInfo di = new DirectoryInfo(dirPath);
278
279             //通过GetFiles方法,获取di目录中的所有文件的大小
280             foreach (FileInfo fi in di.GetFiles())
281             {
282                 len += fi.Length;
283             }
284
285             //获取di中所有的文件夹,并存到一个新的对象数组中,以进行递归
286             DirectoryInfo[] dis = di.GetDirectories();
287             if (dis.Length > 0)
288             {
289                 for (int i = 0; i < dis.Length; i++)
290                 {
291                     len += GetDirectoryLength(dis[i].FullName);
292                 }
293             }
294             return len;
295         }
296     }
297 }







配置文件的代码

因为要求用配置文件,配置原路径,目的路径等信息,有必要说明一下这个问题。另外需要读配置文件,所以需要引用System.Configuration;命名空间。一下是配置文件app.config代码:





<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!--原路径-->
<add key="src" value="e:\test\a"/>
<!--目标路径-->
<add key="obj" value="e:\test\b"/>
<!--日记文件路径-->
<add key="logs" value="e:\test\logs.txt"/>
<!--自动同步时间,单位为毫秒-->
<add key="synTime" value="5000"/>
</appSettings>
</configuration>






效果:



希望本篇文章对你有所用处。

本地文件同步——C#源代码

入职之后接到的第一个代码任务是一个小测试。做一个文件单向同步软件。

需求描述:

将文件夹A内的文件夹和文件同步到文件夹B。
其实需求也就那么一句话,没啥还需要解释的了吧。详细点说,需要同步文件/文件夹的“新增,删除,重命名,修改”。
一开始我的想法是先Google,然后在博客园找到这篇文章《C#文件同步工具教程》。这篇文章的核心来自msdn里面FileSystemWatcher
的解释。就是用对象FileSystemWatcher 去监听文件是否被创建,重命名,删除,修改。如果发生了就调用相对应的事件,将被修改,创建,重命名的文件复制到目标目录B当中。这个例子比较简单,很多事情都没考虑到。而且我认为用FileSystemWatcher 去监听所有的文件,太浪费CPU和内存。

我的想法

是采用递归,遍历整个源目录,对比目标目录。

如果目标目录下没有相对应的文件,将文件复制到目标目录;
如果文件在两个路径下都存在,但是文件大小和最后写入时间不一致时,将原目录下的文件复制到目标目录下;
如果文件存在于目标目录下而不存在源目录下,则将目标路径下的文件删除。

实现

知道如何比较之后就可以进行递归遍历文件夹了。这个是这个软件实现的难点之一,其实也没多难,也就是说这个软件根本就没多难。以下是递归函数:





1 /// <summary>
2 /// 递归核心 同步目录
3 /// </summary>
4 /// <param name="src">原路径</param>
5 /// <param name="obj">目标路径</param>
6 static void loop(string src, string obj)    // 递归核心 同步目录
7 {
8     CopyFistly(src, obj);   //先同步文件
9
10     //遍历文件夹,递归调用
11     DirectoryInfo dirSrc = new DirectoryInfo(src);
12     DirectoryInfo[] dirs = dirSrc.GetDirectories();
13     foreach (DirectoryInfo dir in dirs)
14     {
15         string str = dir.Name;
16         if (Directory.Exists(obj + "\\" + dir.Name) == false)
17         {
18             str = Directory.CreateDirectory(obj + "\\" + dir.Name).ToString();
19         }
20         //注意这里,这里是递归,而且是下面要注意的地方
21         loop(src + "\\" + dir.ToString(), obj + "\\" + str);
22     }
23 }






测试了一下结果,在9000+个文件,40+个文件夹下,在我这部破机器上面单纯递归遍历(不复制文件)的时候需要的时间是截枝的十倍以上。简直是只乌龟。。。



优化

所以要想办法缩短时间提高效率。既然复制文件上面我们无法操作,那我们只好在递归上面进行优化。上个星期我发了一篇文章叫做《算法——回溯法》。这个时候刚好可以用上这种方法了。因为本身用的就是递归,而且文件夹的结构本身就是一个树的结构,在恰好满足了回溯法的要求。在遍历上面,并不需要在所有的文件夹都遍历一遍。因为有些文件夹并没有发生改变,所有就没有必要遍历下去了。所以就需要在递归调用自己之前先加一个条件,也就是加上约束函数。修改之后,代码如下:





1 /// <summary>
2 /// 递归核心 同步目录
3 /// </summary>
4 /// <param name="src">原路径</param>
5 /// <param name="obj">目标路径</param>
6 static void loop(string src, string obj)    // 递归核心 同步目录
7 {
8     CopyFistly(src, obj);   //先同步文件
9
10     //遍历文件夹,递归调用
11     DirectoryInfo dirSrc = new DirectoryInfo(src);
12     DirectoryInfo[] dirs = dirSrc.GetDirectories();
13     foreach (DirectoryInfo dir in dirs)
14     {
15         string str = dir.Name;
16         if (Directory.Exists(obj + "\\" + dir.Name) == false)
17         {
18             str = Directory.CreateDirectory(obj + "\\" + dir.Name).ToString();
19         }
20         DirectoryInfo dirObj = new DirectoryInfo(str);
21         //约束函数 在大小不一致的时候进行同步,其他状态不同步
22         if (GetDirectoryLength(src + "\\" + dir.ToString()) != GetDirectoryLength(obj + "\\" + str))
23             loop(src + "\\" + dir.ToString(), obj + "\\" + str);
24     }
25 }






函数GetDirectoryLength(string path)的作用是检查文件夹path的大小。这里只是简单地对比两个文件夹的大小,如果大小一致,则截枝不递归,否则递归。这种方式的效率非常高,因为很多时候并不是都在有文件的复制,所以不需要经常去遍历目录。所以截枝就好了。下面给出GetDirectoryLength(string path)函数的代码。其实该函数也是一个递归,虽然会增加负荷,但是文件多,文件夹深的时候,是很有必要的。







获取文件夹大小



1 /// <summary>
2 /// 获取路径下文件夹的大小
3 /// </summary>
4 /// <param name="dirPath">目标路径</param>
5 /// <returns>文件夹大小</returns>
6 public static long GetDirectoryLength(string dirPath)
7 {
8     //判断给定的路径是否存在,如果不存在则退出
9     if (!Directory.Exists(dirPath))
10         return 0;
11     long len = 0;
12
13     //定义一个DirectoryInfo对象
14     DirectoryInfo di = new DirectoryInfo(dirPath);
15
16     //通过GetFiles方法,获取di目录中的所有文件的大小
17     foreach (FileInfo fi in di.GetFiles())
18     {
19         len += fi.Length;
20     }
21
22     //获取di中所有的文件夹,并存到一个新的对象数组中,以进行递归
23     DirectoryInfo[] dis = di.GetDirectories();
24     if (dis.Length > 0)
25     {
26         for (int i = 0; i < dis.Length; i++)
27         {
28             len += GetDirectoryLength(dis[i].FullName);
29         }
30     }
31     return len;
32 }







难点主要在递归和截枝的思想上面。其他方面的解释可以直接查看代码。注释已经很清楚了。下面是整个文件的源代码:







文件同步



1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.IO;
6 using System.Threading;
7 using System.Configuration;
8
9 namespace FileSynLoop
10 {
11     class Program
12     {
13         static private string strSource = GetAppConfig("src");   //原路径
14         static private string strObjective = GetAppConfig("obj");    //目标路径
15         static private int synTime = 0;  //同步时间
16         static private string flag = ""; //多线程控制标志 同步控制
17         static private Thread threadShow;   //显示效果线程
18         static private bool bound;  //是否使用截枝函数
19
20         static void Main(string[] args)
21         {
22             //基本设置
23             Console.WriteLine("原路径:" + strSource);
24             Console.WriteLine("目标路径:" + strObjective);
25             try { synTime = Convert.ToInt32(GetAppConfig("synTime")); }
26             catch (Exception e) { Console.WriteLine("配置的同步时间格式不正确:" + e.Message); return; }
27             Console.WriteLine("同步间隔时间:" + synTime + "毫秒");
28
29             if (Directory.Exists(strSource) == false){Console.WriteLine("配置的原路径不存在");return;}
30             if (Directory.Exists(strObjective) == false){Console.WriteLine("配置的目标路径不存在"); return;}
31
32             Console.WriteLine("是否使用截枝函数?使用截止函数无法同步空文件夹/空文件。默认使用截枝!y/n");
33             if (Console.ReadLine() == "n")
34                 bound = false;
35             else
36                 bound = true;
37
38             do{Console.WriteLine("输入ok开始!");}
39             while (Console.ReadLine() != "ok");
40
41             //线程
42             Thread thread = new Thread(new ThreadStart(ThreadProc));
43             threadShow = new Thread(new ThreadStart(ThreadShow));
44             thread.Start();
45             threadShow.Start(); //开始线程
46             threadShow.Suspend();   //挂起线程
47             //退出
48             while ((flag = Console.ReadLine()) != "exit") ;
49         }
50
51         //线程控制
52         public static void ThreadProc()
53         {
54             int i = 0;
55             DateTime dt;
56             TimeSpan ts;
57
58             while (flag != "exit")
59             {
60                 dt = DateTime.Now;
61                 Console.WriteLine();
62                 Console.Write("第" + ++i + "次同步开始:");
63                 threadShow.Resume();    //恢复线程
64                 try
65                 {
66                     loop(strSource, strObjective);
67                 }
68                 catch (Exception e)
69                 {
70                     Console.WriteLine("文件夹“" + strSource + "“被占用,暂时无法同步!8:" + e.Message);
71                 }
72                 threadShow.Suspend();   //挂起线程
73
74                 ts = DateTime.Now - dt;
75                 Console.WriteLine("|");
76                 if (GetDirectoryLength(strSource) == GetDirectoryLength(strObjective))
77                     Console.WriteLine("所有同步完毕!");
78                 Console.WriteLine("第" + i + "次同步结束,耗时"+ts.ToString()+",正在等待下次开始!");
79                 Thread.Sleep(synTime);//同步时间
80             }
81         }
82
83         //显示效果的线程
84         public static void ThreadShow()
85         {
86             while (flag != "exit")
87             {
88                 Console.Write(">");
89                 Thread.Sleep(500);
90             }
91         }
92
93         /// <summary>
94         /// 递归核心 同步目录
95         /// </summary>
96         /// <param name="src">原路径</param>
97         /// <param name="obj">目标路径</param>
98         static void loop(string src, string obj)    // 递归核心 同步目录
99         {
100             CopyFistly(src, obj);   //先同步文件
101
102             //遍历文件夹,递归调用
103             DirectoryInfo dirSrc = new DirectoryInfo(src);
104             DirectoryInfo[] dirs = dirSrc.GetDirectories();
105             foreach (DirectoryInfo dir in dirs)
106             {
107                 string str = dir.Name;
108                 if (Directory.Exists(obj + "\\" + dir.Name) == false)
109                 {
110                     str = Directory.CreateDirectory(obj + "\\" + dir.Name).ToString();
111                 }
112                 DirectoryInfo dirObj = new DirectoryInfo(str);
113                 if (bound)
114                 {
115                     //约束函数 在大小不一致的时候进行同步,其他状态不同步
116                     if (GetDirectoryLength(src + "\\" + dir.ToString()) != GetDirectoryLength(obj + "\\" + str))
117                         loop(src + "\\" + dir.ToString(), obj + "\\" + str);
118                 }
119                 else
120                 {
121                     loop(src + "\\" + dir.ToString(), obj + "\\" + str);
122                 }
123             }
124         }
125
126         /// <summary>
127         /// 同步文件
128         /// </summary>
129         /// <param name="strSource">源目录</param>
130         /// <param name="strObjective">目标目录</param>
131         static private void CopyFistly(string strSource, string strObjective)   //同步文件
132         {
133             string[] srcFileNames = Directory.GetFiles(strSource).Select(s => System.IO.Path.GetFileName(s)).ToArray(); //原路径下的所有文件
134             string[] objFileNames = Directory.GetFiles(strObjective).Select(s => System.IO.Path.GetFileName(s)).ToArray();  //目标路径下的所有文件
135
136             #region 同步新建 修改
137             foreach (string strSrc in srcFileNames) //遍历源文件夹
138             {
139                 FileInfo aFile = new FileInfo(strSource + "\\" + strSrc);
140                 string aAccessTime = aFile.LastWriteTime.ToString();
141                 string aCreateTime = aFile.CreationTime.ToString();
142
143
144                 string bCreateTime = "";    //目标路径文件的信息
145                 string bAccessTime = "";
146
147                 bool flag = false;
148                 foreach (string strObj in objFileNames) //遍历目标文件夹
149                 {
150                     FileInfo bFile = new FileInfo(strObjective + "\\" + strObj);
151                     bAccessTime = bFile.LastWriteTime.ToString();
152                     bCreateTime = bFile.CreationTime.ToString();
153
154                     if (strSrc == strObj)   //文件存在目标路径当中
155                     {
156                         if (aCreateTime != bCreateTime || aAccessTime != bAccessTime)   //文件存在但是不一致
157                         {
158                             try
159                             {
160                                 File.Copy(strSource + "\\" + strSrc, strObjective + "\\" + strSrc, true);
161                                 FileInfo file = new FileInfo(strObjective + "\\" + strSrc);
162                                 file.CreationTime = Convert.ToDateTime(aCreateTime);
163                                 file.LastAccessTime = Convert.ToDateTime(aAccessTime);
164                             }
165                             catch (Exception e)
166                             {
167                                 Console.WriteLine("文件“" + strSrc + "“被占用,暂时无法同步!4:" + e.Message);
168                             }
169                         }
170                         flag = true;
171                         break;
172                     }
173                 }
174
175                 if (flag == false)  //文件不存在目标路径当中
176                 {
177                     try
178                     {
179                         File.Copy(strSource + "\\" + strSrc, strObjective + "\\" + strSrc, true);
180                         FileInfo file = new FileInfo(strObjective + "\\" + strSrc);
181                         file.CreationTime = Convert.ToDateTime(aCreateTime);
182                         file.LastAccessTime = Convert.ToDateTime(aAccessTime);
183                     }
184                     catch (Exception e)
185                     {
186                         Console.WriteLine("文件“" + strSrc + "“被占用,暂时无法同步!5" + e.Message);
187                     }
188                 }
189             }
190             #endregion
191
192             #region 同步删除 重命名
193             //删除文件
194             foreach (string strObj in objFileNames) //遍历目标文件夹
195             {
196                 string allObj = strObjective + "\\" + strObj;
197                 bool flag = false;
198                 foreach (string strSrc in srcFileNames) //遍历源文件夹
199                 {
200                     if (strObj == strSrc)
201                         flag = true;
202                 }
203                 if (flag == false)
204                 {
205                     try
206                     {
207                         File.Delete(allObj);
208                     }
209                     catch (Exception e)
210                     {
211                         Console.WriteLine("文件“" + strObj + "“被占用,暂时无法同步!6" + e.Message);
212                     }
213                 }
214             }
215
216             //删除文件夹
217             DirectoryInfo dirSrc = new DirectoryInfo(strSource);
218             DirectoryInfo[] dirsSrc = dirSrc.GetDirectories();
219             DirectoryInfo dirObj = new DirectoryInfo(strObjective);
220             DirectoryInfo[] dirsObj = dirObj.GetDirectories();
221             foreach (DirectoryInfo bdirObj in dirsObj)
222             {
223                 bool flag = false;
224                 foreach (DirectoryInfo adirSrc in dirsSrc)
225                 {
226                     if (bdirObj.Name == adirSrc.Name)
227                     {
228                         flag = true;
229                     }
230                 }
231                 if (flag == false)  //如果文件夹只出现在目的路径下而不再源目录下,删除该文件夹
232                 {
233                     try
234                     {
235                         Directory.Delete(dirObj + "\\" + bdirObj, true);
236                     }
237                     catch (Exception e)
238                     {
239                         Console.WriteLine("文件夹“" + bdirObj + "“被占用,暂时无法同步!8" + e.Message);
240                     }
241                 }
242             }
243             #endregion
244
245         }
246
247         /// <summary>
248         /// 获取自定义配置的值
249         /// </summary>
250         /// <param name="strKey">键值</param>
251         /// <returns>键值对应的值</returns>
252         private static string GetAppConfig(string strKey)
253         {
254             foreach (string key in ConfigurationManager.AppSettings)
255             {
256                 if (key == strKey)
257                 {
258                     return ConfigurationManager.AppSettings[strKey];
259                 }
260             }
261             return null;
262         }
263
264         /// <summary>
265         /// 获取路径下文件夹的大小
266         /// </summary>
267         /// <param name="dirPath">目标路径</param>
268         /// <returns>文件夹大小</returns>
269         public static long GetDirectoryLength(string dirPath)
270         {
271             //判断给定的路径是否存在,如果不存在则退出
272             if (!Directory.Exists(dirPath))
273                 return 0;
274             long len = 0;
275
276             //定义一个DirectoryInfo对象
277             DirectoryInfo di = new DirectoryInfo(dirPath);
278
279             //通过GetFiles方法,获取di目录中的所有文件的大小
280             foreach (FileInfo fi in di.GetFiles())
281             {
282                 len += fi.Length;
283             }
284
285             //获取di中所有的文件夹,并存到一个新的对象数组中,以进行递归
286             DirectoryInfo[] dis = di.GetDirectories();
287             if (dis.Length > 0)
288             {
289                 for (int i = 0; i < dis.Length; i++)
290                 {
291                     len += GetDirectoryLength(dis[i].FullName);
292                 }
293             }
294             return len;
295         }
296     }
297 }







配置文件的代码

因为要求用配置文件,配置原路径,目的路径等信息,有必要说明一下这个问题。另外需要读配置文件,所以需要引用System.Configuration;命名空间。一下是配置文件app.config代码:





<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!--原路径-->
<add key="src" value="e:\test\a"/>
<!--目标路径-->
<add key="obj" value="e:\test\b"/>
<!--日记文件路径-->
<add key="logs" value="e:\test\logs.txt"/>
<!--自动同步时间,单位为毫秒-->
<add key="synTime" value="5000"/>
</appSettings>
</configuration>






效果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: