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

简介:

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


需求描述:

将文件夹A内的文件夹和文件同步到文件夹B。

其实需求也就那么一句话,没啥还需要解释的了吧。详细点说,需要同步文件/文件夹的“新增,删除,重命名,修改”。

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

 


我的想法

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

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

实现 

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

复制代码
 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)函数的代码。其实该函数也是一个递归,虽然会增加负荷,但是文件多,文件夹深的时候,是很有必要的。

获取文件夹大小

 

 

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

文件同步

 


配置文件的代码

因为要求用配置文件,配置原路径,目的路径等信息,有必要说明一下这个问题。另外需要读配置文件,所以需要引用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>
复制代码

 


效果:

 

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

本文转自 Ron Ngai 博客园博客,原文链接:http://www.cnblogs.com/rond/archive/2012/07/19/2598489.html  ,如需转载请自行联系原作者

相关文章
|
1月前
|
C#
24. C# 编程:用户设定敌人初始血值的实现
24. C# 编程:用户设定敌人初始血值的实现
19 0
|
2月前
|
SQL 数据库连接 应用服务中间件
C#WinForm基础编程(三)
C#WinForm基础编程
75 0
|
2月前
C#WinForm基础编程(二)
C#WinForm基础编程
56 0
|
2月前
|
C# 数据安全/隐私保护
C#WinForm基础编程(一)
C#WinForm基础编程
60 0
|
4月前
|
数据采集 前端开发 C#
C#编程艺术:Fizzler库助您高效爬取www.twitter.com音频
Twitter是全球最大的社交媒体平台之一,包含丰富的音频资源。用户可以在Twitter上发布、转发、评论和收听各种音频内容,如音乐、播客、新闻、故事等,直接从Twitter抓取音频数据并非易事,尤其是在考虑到可能的封锁和反爬虫机制。Twitter会对频繁访问的IP地址进行限制或封禁,以防止恶意爬虫的行为。因此,我们需要使用一些技术手段来规避这些障碍,确保稳定而高效的数据访问。
C#编程艺术:Fizzler库助您高效爬取www.twitter.com音频
|
3月前
|
程序员 C#
深入理解 C# 编程:枚举、文件处理、异常处理和数字相加
枚举是一个特殊的“类”,表示一组常量(不可更改/只读变量)。 要创建枚举,请使用 enum 关键字(而不是 class 或 interface),并用逗号分隔枚举项:
38 0
|
3天前
|
存储 安全 网络安全
C#编程的安全性与加密技术
【4月更文挑战第21天】C#在.NET框架支持下,以其面向对象和高级特性成为安全软件开发的利器。本文探讨C#在安全加密领域的应用,包括使用System.Security.Cryptography库实现加密算法,利用SSL/TLS保障网络传输安全,进行身份验证,并强调编写安全代码的重要性。实际案例涵盖在线支付、企业应用和文件加密,展示了C#在应对安全挑战的同时,不断拓展其在该领域的潜力和未来前景。
|
3天前
|
程序员 C#
C#编程中的面向对象编程思想
【4月更文挑战第21天】本文探讨了C#中的面向对象编程,包括类、对象、封装、继承和多态。类是对象的抽象,定义属性和行为;对象是类的实例。封装隐藏内部细节,只暴露必要接口。继承允许类复用和扩展属性与行为,而多态使不同类的对象能通过相同接口调用方法。C#通过访问修饰符实现封装,使用虚方法和抽象方法实现多态。理解并应用这些概念,能提升代码的清晰度和可扩展性,助你成为更好的C#程序员。
|
4天前
|
IDE 程序员 C#
C#编程入门:从零开始的旅程
【4月更文挑战第20天】本文引导初学者入门C#编程,从环境搭建开始,推荐使用Visual Studio Community版作为IDE。接着,通过编写&quot;Hello, World!&quot;程序,介绍基本语法,包括数据类型、运算符和表达式。文章还涉及控制结构、函数和方法,以及面向对象编程概念。通过学习,读者将对C#有初步了解,并激发进一步探索编程世界的兴趣。