分享一个基于FileSystemWatcher的文件自动备份程序

一:背景

  我们公司asp.net的项目都是使用FTP进行上传下载来发布和更新的。尽管我们在发布修改之前都在本地进行进行测试,但本地的开发环境始终和外网上的实际环境还是有差别的(特别在一些数据上的差别),所以有时不可避免地出现在本地测试时没有Bug,但上传到外网就出现Bug的情况。

  很多时候我们在ftp后如果出现bug,第一个反应就是马上还原回更新前的状态,也就是将旧问题替换回去。但这样也就需要在ftp上传前先将旧文件备份。但因为这样做太繁琐,有时候更新量大而且文件分散,备份旧文件就变成一件还是挺烦人的事情。虽然ftp工具都有简单的自动提示功能,例如filezilla就可以设定同名文件的处理方式,但功能薄弱。而我也找过一些文件自动备份软件,例如大名鼎鼎的alway sync ,但感觉它不是专门为这种情况而设计的,用起来没有那么方便。例如:我需要搜索某一段时间里对某个更新进行备份的文件,并将这些文件批量恢复回去。

  (:当然,我觉得:
    1假如有这种需求,应该会有这类型成熟的软件,这是我不知道。有经验的朋友可以分享一下。
    2: 或者我每次更新都是用ftp来手动上传下载是一种比较落后的做法,感觉是一种较为作坊式的项目管理方式,用收工ftp的整个过程根本不可控不可管理。公司的php项目组在发布是将文件提交至生产服务器上的svn,通过svn的钩子对文件进行更新的。也就是说,业界可能有很多更成熟的发布做法。希望有经验的朋友分享一下。)

  基于希望能对FTP上传文件自动备份的问题,我前一段时间使用FileSystemWatcher类编写了一个小程序,自动的监视某个目录,当该目录的文件被修改后对文件作备份。注意这里是"修改后",并不是"修改前"。FileSystemWatcher里的事件都是在原文件被修改后才触发的,并不是我们希望的在操作系统对文件修改前暂停修改操作并触发事件,等我们备份了文件再继续修改操作。我开始也很困惑,甚至去找一些"修改前触发事件"的api,但发现就算c++也好像没有这类方案(使用钩子应该可以,但没试过)。后来觉得微软这样设计也是合理的,因为对文件进行修改是操作系统的工作,而备份是出于操作系统上层的应用程序的工作,为了保持操作系统的工作的连贯性,当然不希望上层应用中断操作系统的操作(这点纯碎是个人猜测)
  所以,使用FileSystemWatcher来实现监视和备份,都是备份修改过的最新文件的。这也是可以接受的,因为除了第一次更改前的旧文件不能被备份外,后续每次更改的文件都会有一份对应的备份,第二次及以后的更改都可以找回前一份文件。

二:功能和特点描述

  

  1.该工具可以监视某一个目录(可以设定是否监视子目录),当文件被更改后(文件内容被更改,或者重命名),该文件会被自动备份到一个指定的备份目录中。由于是”更改后触发事件“,因为并没有对删除操作进行备份,因为一个文件被删除了,在deleted事件中是找不到原来的文件的,而且通常来说,被删除的文件在删除前早就被备份过了。
  2.文件每次被更新,其备份文件都会带有更改时间和更改类型作为标识,以便日后区分是什么时候和什么操作导致的备份,方便记录。
  3.可以对备份文件进行按文件名,更改时间,更改类型的条件查找。并对文件进行恢复(批量将备份文件还原回去,恢复更改前的状态)
  4.可以包含子目录监视并在备份时自动创建于被监视目录相同的目录结构。比如:被监视的目录是c:\a ,备份目录是c:\b,当c:\a\d\e\f\somefile.txt被修改后,将会在c:\b\d\e\f\somefile.txt
  5.可以开机自动启动并回复关机前的监视状态。因为有时候软件所在服务器可能会关机,在重新启动后就可以自动启动软件并回复上次的监视状态,减少人工干预。
  6.可以自己编写记录备份和搜索备份的模块(代码里面预定义了接口),原来是将备份文件名以更改时间和更改动作,搜索时使用File在文件系统上搜索文件。但同事给的意见是:最好可以提供记录在数据库的方式,利用数据库强大的检索功能。于是就定义了两个接口,允许自己编写保存和查找的代码。

三:代码概括

  这个程序核心就是FileSystemWatcher类了。我自定义了一个继承FileSystemWatcher的子类XWXFileSystemWatcher,封装父类,添加了一些方法和一些事件。
  程序中维护着一个XWXFileSystemWatcher的列表:List<XWXFileSystemWatcher> watcherList,并与程序运行过程中的监视项的同步。
  此外,程序中还定义了一个事件OnWatchSettingChanged。每个导致监视变化的操作都触发该事件,例如开始/暂停监视,改变文件更改类型以及选择是否包含子目录。在该事件的事件处理函数里面同时将监视的详细信息通过序列化的方式保持到文件中,以便下次启动可以加载并反序列化该文件,达到恢复上次监视状态。
  程序中定义了一个可序列化的模型类WatchInfo,用来封装一个监视项的信息,包括:监视目录,备份目录,更改类型,运行状态和是否包括子目录。如上面说的,在每次对监视项进行设置,都会触发OnWatchSettingChanged事件去将监视项实时进行保存。
  对于备份记录的保存,默认的是以 @yyyy-mm-dd.changeType的后缀来命名备份文件,而查找备份文件也同样的是对备份文件名的“@yyyy-mm-dd.changeType”进行分析以识别备份文件是什么时候对哪种操作进行备份的。但程序中也定义了两个接口:IRecord和ISearchBackupFiles。可以通过继承这两个接口来实现自己的保存备份记录和查找备份记录的模块。程序中使用了工厂模式+配置文件反射的方式来加载这些模块。
  其他具体的请见源代码。由于个人精力与水平限制,程序中可能存在一些bug,欢迎斧正。

posted on 2013-04-17 22:57  wyman25  阅读(2577)  评论(15编辑  收藏  举报

导航