filecmp模块用于比较文件及文件夹的内容,它是一个轻量级的工具,使用非常简单。filecmp可以实现文件,目录,遍历子目录的差异对比功能。python 2.3或更高版本默认自带filecmp模块,无序额外安装。此外,python标准库还提供了difflib模块用于比较文件的内容。
filecmp提供了三个操作方法,分别为cmp(单文件对比),cmpfiles(多文件对比),dircmp(目录对比),用于方便地比较文件与文件夹:
1,单文件对比,采用filecmp.cmp(f1, f2[, shallow]):
比较两个文件的内容是否匹配。参数f1, f2指定要比较的文件的路径。可选参数shallow指定比较文件时是否需要考虑文件本身的属性(通过os.stat函数可以获得文件属性)。如果文件内容匹配,函数返回True,否则返回False。
2,多文件对比,采用filecmp.cmpfiles(dir1, dir2, common[, shallow]):
比较两个文件夹内指定文件是否相等。参数dir1, dir2指定要比较的文件夹,参数common指定要比较的文件名列表。函数返回包含3个list元素的元组,分别表示匹配、不匹配以及错误的文件列表。错误的文件指的是不存在的文件,或文件被琐定不可读,或没权限读文件,或者由于其他原因访问不了该文件。
3,目录对比,通过 filecmp(a,b[,ignore[,hide]])类创建一个目录比较对象:
用于比较文件夹,通过该类比较两个文件夹,可以获取一些详细的比较结果(如只在A文件夹存在的文件列表),并支持子文件夹的递归比较。
dircmp提供了三个方法用于报告比较的结果: report():只比较指定文件夹中的内容(文件与文件夹) report_partial_closure():比较文件夹及第一级子文件夹的内容 report_full_closure():递归比较所有的文件夹的内容
dircmp还提供了下面这些属性用于获取比较的详细结果:
left_list:左边文件夹中的文件与文件夹列表; right_list:右边文件夹中的文件与文件夹列表; common:两边文件夹中都存在的文件或文件夹; left_only:只在左边文件夹中存在的文件或文件夹; right_only:只在右边文件夹中存在的文件或文件夹; common_dirs:两边文件夹都存在的子文件夹; common_files:两边文件夹都存在的子文件; common_funny:两边文件夹都存在的子文件夹; same_files:匹配的文件; diff_files:不匹配的文件; funny_files:两边文件夹中都存在,但无法比较的文件; subdirs:将common_dirs 目录映射到新的dircmp对象,格式为字典的类型。
以下脚本在python2和3中都可以使用,目的是比较源目录与备份目录的差异文件,并将差异文件同步到备份目录中。
<code> #!/usr/bin/python #coding:utf-8 import os,sys import filecmp import re import shutil ''' 校验源与备份目录的差异 ''' holderlist = [] def compareme(dir1,dir2): #递归获取更新项函数 dircomp = filecmp.dircmp(dir1,dir2) only_in_one = dircomp.left_only #源目录新文件或目录 diff_in_one = dircomp.diff_files #不匹配文件,源目录文件已发生变化 dirpath = os.path.abspath(dir1) #定义源目录绝对路径 #将更新文件或目录追加到holderlist [ holderlist.append(os.path.abspath(os.path.join(dir1,x))) for x in only_in_one ] [ holderlist.append(os.path.abspath(os.path.join(dir1,x))) for x in diff_in_one ] if len(dircomp.common_dirs) > 0: #判断是否存在相同子目录,以便递归 for item in dircomp.common_dirs: #递归子目录 compareme(os.path.abspath(os.path.join(dir1,item)),os.path.abspath(os.path.join(dir2,item))) return holderlist def main(): if len(sys.argv) > 2: #输入源目录与备份目录 dir1 = sys.argv[1] dir2 = sys.argv[2] else : print('Usage:',sys.argv[0],'datadir backdir') sys.exit() source_files = compareme(dir1,dir2) #对比源目录与备份目录 dir1 = os.path.abspath(dir1) #取绝对路径后,后面不会自动加上'/' if not dir2.endswith('/'): dir2 = dir2+'/' #备份目录路径加'/' dir2 = os.path.abspath(dir2) destination_files = [] createdir_bool = False for item in source_files: #遍历返回的差异文件或目录清单 destination_dir = re.sub(dir1,dir2,item) #将源目录差异路径清单对应替换成备份目录,即需要在dir2中创建的差异目录和文件 destination_files.append(destination_dir) if os.path.isdir(item): #如果差异路径为目录且不存在,则在备份目录中创建 if not os.path.exists(destination_dir): os.makedirs(destination_dir) createdir_bool = True #再次调用copareme函数标记 if createdir_bool : #重新调用compareme函数,重新遍历新创建目录的内容 destination_files = [] source_files = [] source_files = compareme(dir1,dir2) #调用compareme函数 for item in source_files: #获取源目录差异路径清单,对应替换成备份目录 destination_dir = re.sub(dir1,dir2,item) destination_files.append(destination_dir) print('update item:') print(source_files) #输出更新项列表清单 copy_pair = zip(source_files,destination_files) #将源目录与备份目录文件清单拆分成元组 for item in copy_pair: if os.path.isfile(item[0]): #判断是否为文件,是则进行复制操作 shutil.copyfile(item[0],item[1]) if __name__ == '__main__' : main() </code>
运行结果为:
<code> [root@sta auto]# ls /tmp/pass a passwd [root@sta auto]# ls /tmp/pass1 [root@sta auto]# python diff_dir.py /tmp/pass /tmp/pass1 update item: ['/tmp/pass/passwd', '/tmp/pass/a'] [root@sta auto]# </code>
此脚本只是初步完成的,还在不断完善中,欢迎继续关注!