Python写的增量备份文件脚本

来源:互联网 发布:linux ftp 20端口 编辑:程序博客网 时间:2024/05/19 02:00

        自己有很多资料需要备份到别的地方。问题是之前也做过备份,但是随着资料的不断更新和增加,就会出现原来做的备份跟现在要备份的资料既有重复的,又有新的,或者是虽然文件名相同,但是内容已经更新了的文件。如果再次备份的话,就需要重新把最新的资料拷贝一遍到目标存储中。如果资料不是很多还好,一旦资料很多且体积庞大,如此没有差别的拷贝就要花费很多冤枉时间进行覆盖目标存储中相同的资料。能不能只备份新的和已更新的资料,而不拷贝相同的资料呢?这就是这个脚本的用处,该脚本能够实现增量备份资料功能。

        由于该脚本使用纯Python编写,故需要电脑上具备可用的Python解释器环境才能运行该代码。使用方法:把代码拷贝到一个空文件中,然后把文件保存成“xxx.py”格式,然后运行命令:python xxx.py即可运行。

        顺便提示:Python版本最好使用2.5.4版本,该版本不但稳定,而且相对比较高效。该脚本可能不支持3.0及以上的Python版本。关于Python的安装及环境设置方法,网络上有很多,就不再这里啰嗦了。

        该脚本有两个版本:一个适用于Linux系统;一个适用于Windows系统。同时,本人还提供一个EXE文件,供那些不想在电脑上安装Python解释器的朋友使用,如果需要下载,请在CSDN下载频道里搜索用户名为dbsync上传的资源。

        由于Linux系统对中文支持不是很好,如果在Linux系统上打开该代码,其中的注释可能会显示为乱码。

        该脚本经过本人实际应用,都能正常使用。需要注意的一点是所要备份的文件名不能过长,否则可能会备份失败。

        本次脚本提供日志功能,所有的备份日志都会被记录并保存在一个文件中。

        如果有什么问题,欢迎给我留言,大家共同学习讨论。

        以下是源代码:


===================华丽分割线:-)========================


Linux系统所用:


#coding=utf8
#! /usr/bin/env python

import os


mark=0        #全局变量,统计总共有多少文件被复制

def logs(value):    #记录日志函数
    v1=open('backup_files.log','ab')
    v1.write(value)
    v1.close()


def erro(value1,value2,value3):        #搜集错误信息函数
    renameerro={}        #存放重命名失败的文件名及失败原因
    copyerro={}        #存放复制失败的文件名及失败原因
    removerro={}        #存放删除失败的文件名及失败原因
    mkdirerro={}        #存放创建路径失败的路径名及失败原因
    if value1=='renameerro' and value2 not in renameerro.keys():
        renameerro[value2]=value3
    elif value1=='copyerro' and values2 not in copyerro.keys():
        copyerro[value2]=value3
    elif value1=='removerro' and value2 not in removerro.keys():
        removerro[value2]=value3
    elif value1=='mkdirerro' and value2 not in mkdirerro.keys():
        mkdirerro[value2]=value3
    else:
        pass
    v1=[renameerro,copyerro,removerro,mkdirerro]
    return v1

def printerro(value):        #打印错误信息函数
    renameerro=value[0]
    copyerro=value[1]
    removerro=value[2]
    mkdirerro=value[3]
    if len(renameerro)!=0:
        print '/n---These are the files to rename faise:'
        tmp='/n---These are the files to rename faise:'
        logs(tmp)
        for a in renameerro.keys():
            print a+',The reason is:'+str(renameerro[a])
            tmp=a+',The reason is:'+str(renameerro[a])
            logs(tmp)
    if len(copyerro)!=0:
        print '/n---These are the files to copy faise:'
        tmp='/n---These are the files to copy faise:'
        logs(tmp)
        for a in copyerro.keys():
            print a+',The reason is:'+str(copyerro[a])
            tmp=a+',The reason is:'+str(copyerro[a])
            logs(tmp)
    if len(removerro)!=0:
        print '/n---These are the files to remove faise:'
        tmp='/n---These are the files to remove faise:'
        logs(tmp)
        for a in removerro.keys():
            print a+',The reason is:'+str(removerro[a])
            tmp=a+',The reason is:'+str(removerro[a])
            logs(tmp)
    if len(mkdirerro)!=0:
        print '/n---These are the files to create path faise:'
        tmp='/n---These are the files to create path faise:'
        logs(tmp)
        for a in mkdirerro.keys():
            print a+',The reason is:'+str(mkdirerro[a])
            tmp=a+',The reason is:'+str(mkdirerro[a])
            logs(tmp)


def src_dir():        #源端路径设置函数
    while 1:
        v1=raw_input('/n---Please enter the source path:/n/n>>')
        if len(v1)==0:
            print '/n---Error!! Source path can not be NULL!'
            continue
        if not os.path.exists(v1):        #判断该路径是否存在
            print '/n---Error!! Source path is not exist!'
            continue
        v2=os.walk(v1)
        mark=0        #判断该路径下是否有文件
        for a in v2:
            if a[2]!=0:
                mark=1
                break
        if mark==0:
            print '/n---Error!! Without any valid files in source path!'
            exit()        #没有文件的话,整个脚本退出
        else:
            break
    return v1

def targ_dir():        #目标端路径设置函数
    while 1:
        mark=0
        v1=raw_input('/n---Please enter the target path:/n/n>>')
        if len(v1)==0:
            print '/n---Error!! The target path can not be NULL!'
            mark=1
            continue
        if not os.path.exists(v1):        #判断该路径是否存在
            print '/n---Error!!Target-side path does not exist'
            mark=1
            continue
        if mark==0:
            break
    return v1

def copyfile(src,targ):        #文件拷贝函数
    v1=open(src,'rb')        #打开源端文件
    v2=open(targ,'wb')        #打开目标端文件
    print '/n---Copying file %s ....'%src
    while True:        #拷贝循环
        v3=v1.read(1024*15000)        #每次从源端文件中读取15MB的内容
        v2.write(v3)        #把数据写入目标端文件
        if len(v3)<1024*15000:        #判断源端文件是否被全部读完
            break
    v1.close()
    v2.close()
    print '/n---Complete copy of the file %s '%src
    tmp='/n---Complete copy of the file %s '%src
    logs(tmp)

def main(src,targ):            #主函数
    global mark        #使用全局变量mark,统计总共有多少文件被复制
    v1=os.listdir(src)        #获得源端目录下所有的文件及文件夹
    for a in v1:        #备份文件主循环
        if os.path.isfile(src+'/'+a):        #判断是否为文件
            if os.path.exists(targ+'/'+a):        #如果该文件在目标端已经存在
                if os.path.getsize(src+'/'+a)>os.path.getsize(targ+'/'+a):        #如果源端文件的大小大于目标端
                    while True:        #确定重命名后的文件名称
                        if os.path.exists(targ+'/'+a+'.bak'):
                            a=a+'.bak'
                            continue
                        else:
                            break
                    try:
                        os.rename(targ+'/'+a,targ+'/'+a+'.bak')        #重命名目标端该文件
                    except Exception,e:
                        print '/n---Error!! Rename the file error : %s'%(targ+'/'+a)
                        erro('renameerro',targ+'/'+a,e)
                        print e
                        continue        #如果重命名失败,则不再处理该文件,进入主循环的下一次循环
                    try:
                        copyfile(src+'/'+a,targ+'/'+a)        #开始复制文件
                    except Exception,e:
                        print '/n---Error!! Copy the file error : %s'%(src+'/'+a)
                        erro('copyerro',src+'/'+a,e)
                        print e
                        continue        #如果复制失败,则不再处理该文件,进入主循环的下一次循环
                    try:
                        os.remove(targ+'/'+a+'.bak')        #移除目标端旧的文件
                        mark=mark+1
                    except Exception,e:
                        print '/n---Error!! Remove the file error : %s'%(targ+'/'+a+'.bak')
                        erro('removerro',targ+'/'+a+'.bak',e)
                        print e
                        continue        #如果删除失败,则不再处理该文件,进入主循环的下一次循环
                elif os.path.getmtime(src+'/'+a)>os.path.getmtime(targ+'/'+a):        #如果源端文件的最新修改日期比目标端文件新
                    while True:
                        if os.path.exists(targ+'/'+a+'.bak'):
                            a=a+'.bak'
                            continue
                        else:
                            break
                    try:
                        os.rename(targ+'/'+a,targ+'/'+a+'.bak')
                    except Exception,e:
                        print '/n---Error!! Rename the file error : %s'%(targ+'/'+a)
                        erro('renameerro',targ+'/'+a,e)
                        print e
                        continue
                    try:
                        copyfile(src+'/'+a,targ+'/'+a)
                    except Exception,e:
                        print '/n---Error!! Copy the file error : %s'%(src+'/'+a)
                        erro('copyerro',src+'/'+a,e)
                        print e
                        continue
                    try:
                        os.remove(targ+'/'+a+'.bak')
                        mark=mark+1
                    except Exception,e:
                        print '/n---Error!! Remove the file error : %s'%(targ+'/'+a+'.bak')
                        erro('removerro',targ+'/'+a+'.bak',e)
                        print e
                        continue
                else:
                    pass
            else:        #如果该文件在目标端不存在
                if not os.path.isdir(targ):        #如果该文件所在路径在目标端不存在
                    try:
                        os.makedirs(targ)        #在目标端建立相应的路径
                    except Exception,e:
                        print '/n---Error!! Error creating path : %s'%(targ)
                        erro('mkdirerro',targ,e)
                        print e
                        continue
                try:
                    copyfile(src+'/'+a,targ+'/'+a)
                    mark=mark+1
                except Exception,e:
                    print '/n---Error!! Copy file error : %s'%(src+'/'+a)
                    erro('copyerro',src+'/'+a,e)
                    print e
                    continue
        else:        #如果a是个文件夹
            main(src+'/'+a,targ+'/'+a)        #再次调用主函数
    return mark



if __name__=='__main__':
    v1=src_dir()
    v2=targ_dir()
    v3=main(v1,v2)
    print '/n--- All files processed! Handled a total of %d files !'%v3
    tmp='/n--- All files processed! Handled a total of %d files !'%v3
    logs(tmp)
    printerro(erro('1','2','3'))
    print '/n---Run log saved in the file "backup_files.log"'



===================华丽分割线:-)========================


Windows系统所用:


#coding=gb18030
#! //usr//bin//env python

import os
import time


mark=0        #全局变量,统计总共有多少文件被复制


def logs(value):    #记录日志函数
    v1=open('backup_files.log','ab')
    v1.write(value)
    v1.close()


def processunicode(value):        #处理unicode类型字符串
    v1=''
    for a in value:
        if type(a)==unicode:
            v1=v1+str(a).encode('gb18030')
        else:
            v1=v1+str(a)
    return v1


def src_dir():        #源端路径设置函数
    while 1:
        v1=raw_input('/n---请输入源端绝对路径:/n/n>>')
        if len(v1)==0:
            print '/n---错误!!源端路径不能为空!'
            continue
        if not os.path.exists(v1):        #判断该路径是否存在
            print '/n---错误!!该路径不存在!'
            continue
        v2=os.walk(v1)
        mark=0        #判断该路径下是否有文件
        for a in v2:
            if a[2]!=0:
                mark=1
                break
        if mark==0:
            print '/n---警告:该路径下没有任何有效文件,脚本退出!'
            exit()        #没有文件的话,整个脚本退出
        else:
            break
    return v1

def erro(value1,value2,value3):        #搜集错误信息函数
    renameerro={}        #存放重命名失败的文件名及失败原因
    copyerro={}        #存放复制失败的文件名及失败原因
    removerro={}        #存放删除失败的文件名及失败原因
    mkdirerro={}        #存放创建路径失败的路径名及失败原因
    if value1=='renameerro' and value2 not in renameerro.keys():
        renameerro[value2]=value3
    elif value1=='copyerro' and values2 not in copyerro.keys():
        copyerro[value2]=value3
    elif value1=='removerro' and value2 not in removerro.keys():
        removerro[value2]=value3
    elif value1=='mkdirerro' and value2 not in mkdirerro.keys():
        mkdirerro[value2]=value3
    else:
        pass
    v1=[renameerro,copyerro,removerro,mkdirerro]
    return v1

def printerro(value):        #打印错误信息函数
    renameerro=value[0]
    copyerro=value[1]
    removerro=value[2]
    mkdirerro=value[3]
    if len(renameerro)!=0:
        print '/n---重命名失败的文件及原因如下:'
        tmp='/n---重命名失败的文件及原因如下:'
        logs(tmp)
        for a in renameerro.keys():
            print a+',原因是:'+renameerro[a]
            tmp=a+',原因是:'+renameerro[a]
            logs(tmp)
    if len(copyerro)!=0:
        print '/n---复制失败的文件及原因如下:'
        tmp='/n---复制失败的文件及原因如下:'
        logs(tmp)
        for a in copyerro.keys():
            print a+',原因是:'+copyerro[a]
            tmp=a+',原因是:'+copyerro[a]
            logs(tmp)
    if len(removerro)!=0:
        print '/n---删除失败的文件及原因如下:'
        tmp='/n---删除失败的文件及原因如下:'
        logs(tmp)
        for a in removerro.keys():
            print a+',原因是:'+removerro[a]
            tmp=a+',原因是:'+removerro[a]
            logs(tmp)
    if len(mkdirerro)!=0:
        print '/n---创建失败的路径名及原因如下:'
        tmp='/n---创建失败的路径名及原因如下:'
        logs(tmp)
        for a in mkdirerro.keys():
            print a+',原因是:'+mkdirerro[a]
            tmp=a+',原因是:'+mkdirerro[a]
            logs(tmp)


def targ_dir():        #目标端路径设置函数
    while 1:
        mark=0
        v1=raw_input('/n---请输入目标端绝对路径:/n/n>>')
        if len(v1)==0:
            print '/n---错误!!目标端路径不能为空!'
            mark=1
            continue
        if not os.path.exists(v1):        #判断该路径是否存在
            print '/n---错误!!该路径不存在!'
            mark=1
            continue
        if mark==0:
            break
    return v1

def copyfile(src,targ):        #文件拷贝函数
    v1=open(src,'rb')        #打开源端文件
    v2=open(targ,'wb')        #打开目标端文件
    print '/n---正在备份文件: %s ....'%src
    while True:        #拷贝循环
        v3=v1.read(1024*15000)        #每次从源端文件中读取15MB的内容
        v2.write(v3)        #把数据写入目标端文件
        if len(v3)<1024*15000:        #判断源端文件是否被全部读完
            break
    v1.close()
    v2.close()
    print '/n---文件 %s 备份完毕!'%src
    writefiles='/n---文件 %s 备份完毕!'%src
    logs(writefiles)

def main(src,targ):            #主函数
    global mark        #使用全局变量mark,统计总共有多少文件被复制
    v1=os.listdir(src)        #获得源端目录下所有的文件及文件夹
    for a in v1:        #备份文件主循环
        if os.path.isfile(src+'//'+a):        #判断是否为文件
            if os.path.exists(targ+'//'+a):        #如果该文件在目标端已经存在
                if os.path.getsize(src+'//'+a)>os.path.getsize(targ+'//'+a):        #如果源端文件的大小大于目标端
                    while True:        #确定重命名后的文件名称
                        if os.path.exists(targ+'//'+a+'.bak'):
                            a=a+'.bak'
                            continue
                        else:
                            break
                    try:
                        os.rename(targ+'//'+a,targ+'//'+a+'.bak')        #重命名目标端该文件
                    except Exception,e:
                        print '/n---错误!!重命名文件 %s 时发生错误:'%(targ+'//'+a)
                        erro('renameerro',targ+'//'+a,processunicode(e))
                        print processunicode(e)
                        continue        #如果重命名失败,则不再处理该文件,进入主循环的下一次循环
                    try:
                        copyfile(src+'//'+a,targ+'//'+a)        #开始复制文件
                    except Exception,e:
                        print '/n---错误!!在备份文件 %s 时发生错误:'%(src+'//'+a)
                        erro('copyerro',src+'//'+a,processunicode(e))
                        print processunicode(e)
                        continue        #如果复制失败,则不再处理该文件,进入主循环的下一次循环
                    try:
                        os.remove(targ+'//'+a+'.bak')        #移除目标端旧的文件
                        mark=mark+1
                    except Exception,e:
                        print '/n---错误!!在删除目标端文件 %s 时发生错误:'%(targ+'//'+a+'.bak')
                        erro('removerro',targ+'//'+a+'.bak',processunicode(e))
                        print processunicode(e)
                        continue        #如果删除失败,则不再处理该文件,进入主循环的下一次循环
                elif os.path.getmtime(src+'//'+a)>os.path.getmtime(targ+'//'+a):        #如果源端文件的最新修改日期比目标端文件新
                    while True:
                        if os.path.exists(targ+'//'+a+'.bak'):
                            a=a+'.bak'
                            continue
                        else:
                            break
                    try:
                        os.rename(targ+'//'+a,targ+'//'+a+'.bak')
                    except Exception,e:
                        print '/n---错误!!在重命名目标端文件 %s 时发生错误:'%(targ+'//'+a)
                        erro('rename',targ+'//'+a,processunicode(e))
                        print processunicode(e)
                        continue
                    try:
                        copyfile(src+'//'+a,targ+'//'+a)
                    except Exception,e:
                        print '/n---错误!!在备份文件 %s 时发生错误:'%(src+'//'+a)
                        erro('copyerro',src+'//'+a,processunicode(e))
                        print processunicode(e)
                        continue
                    try:
                        os.remove(targ+'//'+a+'.bak')
                        mark=mark+1
                    except Exception,e:
                        print '/n---错误!!在删除目标端文件 %s 时发生错误:'%(targ+'//'+a+'.bak')
                        erro('removerro',targ+'//'+a+'.bak',processunicode(e))
                        print processunicode(e)
                        continue
                else:
                    pass
            else:        #如果该文件在目标端不存在
                if not os.path.isdir(targ):        #如果该文件所在路径在目标端不存在
                    try:
                        os.makedirs(targ)        #在目标端建立相应的路径
                    except Exception,e:
                        print '/n---错误!!在创建目标端路径 %s 时发生错误:'%(targ)
                        erro('mkdirerro',targ,processunicode(e))
                        print processunicode(e)
                        continue
                try:
                    copyfile(src+'//'+a,targ+'//'+a)
                    mark=mark+1
                except Exception,e:
                    print '/n---错误!!在备份文件 %s 时发生错误:'%(src+'//'+a)
                    erro('copyerro',src+'//'+a,processunicode(e))
                    print processunicode(e)
                    continue
        else:        #如果a是个文件夹
            main(src+'//'+a,targ+'//'+a)        #再次调用主函数
    return mark



if __name__=='__main__':
    v1=src_dir()
    v2=targ_dir()
    v3=main(v1,v2)
    print '/n---所有文件备份完毕!共有 %d 个文件被备份!'%v3
    printerro(erro('1','2','3'))
    tmp='/n---所有文件备份完毕!共有 %d 个文件被备份!'%v3
    logs(tmp)
    print '/n---运行日志保存在文件“backup_files.log”中。'
    v4=raw_input('/n---按 回车键 退出脚本....')