文件内容差异比对--difflib、filecmp
difflib作为python的标准库模块,无需安装,作用是对比文本之间的差异,且支持输出可读性比较强的HTML文档,与Linux下的diff命令类似。我们可以使用difflib对比代码、配置文件的差别,在版本控制方面是非常有用。
1、两个字符串的差异对比
1 #!/usr/bin/env python 2 #coding=utf-8 3 import difflib 4 5 #比对两个字符串中的不同点 6 text1 = "text1 hello world!" #定义字符串 7 text1_lines = text1.splitlines() #进行分隔,以便进行对比 8 text2 = "text2 Hello World." 9 text2_lines = text2.splitlines() 10 11 a = difflib.Differ() #创建Differ()对象 12 diff = a.compare(text1_lines,text2_lines) #采用compare方法对字符串进行比较 13 print '\n'.join(list(diff))
实践对比Nginx配置文件差异
1 #!/usr/bin/env python 2 #coding=utf-8 3 4 import difflib 5 import sys 6 try: 7 textfile1 = sys.argv[1] #第一个配置文件路径参数 8 textfile2 = sys.argv[2] #第二个配置文件路径参数 9 10 except Exception,e: 11 print "Error:" + str(e) 12 print "Usage: file_diff.py filename1 filename2" 13 sys.exit() 14 15 def readfile(filename): #文件读取分隔函数 16 try: 17 fileHandle = open (filename, 'rb') 18 text = fileHandle.read().splitlines() #读取以后进行分隔 19 fileHandle.close() 20 return text 21 except IOError as error: 22 print ('Read file Error:' + str(error)) 23 sys.exit() 24 25 if textfile1 == "" or textfile2 == "": 26 print "Usage: file_diff.py filename1 filename2" 27 sys.exit() 28 29 text1_lines = readfile(textfile1) #调用readfile函数,获取分隔后的字符串 30 text2_lines = readfile(textfile2) 31 32 d = difflib.HtmlDiff() #创建HtmlDiff()类对象 33 print d.make_file(text1_lines,text2_lines) #通过make_file方法输出HTML格式的对比结果 34 35 运行如下代码: 36 python sample.py nginx.conf.v1 nginx.conf.v2 > diff.html
2、文件与目录差异对比方法
filecmp提供了三个操作方法,分别是cmp(单文件对比)、cmpfiles(多文件对比)、dircmp(目录对比)
1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 3 4 import os, sys 5 import filecmp 6 import re 7 import shutil 8 9 holderlist = [] 10 11 ##对应第一个步骤 12 def compare_me(dir1, dir2): #递归获取更新项函数 13 dircomp = filecmp.dircmp(dir1, dir2) 14 only_in_one = dircomp.left_only #源目录新文件或目录 15 diff_in_one = dircomp.diff_files #不匹配文件,源目录已发生变化 16 dirpath = os.path.abspath(dir1) #定义源目录绝对路径 17 18 #将更新文件名或者目录追加到holderlist 19 [ holderlist.append(os.path.abspath(os.path.join(dir1, x))) for x in only_in_one ] 20 [ holderlist.append(os.path.abspath(os.path.join(dir1, x))) for x in diff_in_one ] 21 if len(dircomp.common_dirs) > 0: 22 for item in dircomp.common_dirs: 23 compare_me(os.path.abspath(os.path.join(dir1, item)), os.path.abspath(os.path.join(dir2, item))) 24 return holderlist 25 26 ##对应第二个步骤 27 def main(): 28 if len(sys.argv) > 2: #要求输入源目录与备份目录 29 dir1 = sys.argv[1] 30 dir2 = sys.argv[2] 31 else: 32 print "Usage: ", sys.argv[0], "datadir backupdir" 33 sys.exit() 34 35 source_files = compare_me(dir1, dir2) #对比源目录与备份目录 36 dir1 = os.path.abspath(dir1) 37 if not dir2.endswith('/'): #备份目录路径加"/"符 38 dir2 = dir2 + '/' 39 dir2 = os.path.abspath(dir2) 40 destination_files = [] 41 createdir_bool = False 42 43 for item in source_files: #遍历返回的差异文件或目录清单 44 destination_dir = re.sub(dir1, dir2, item) #将源目录差异路径清单对应替换成备份目录 45 destination_files.append(destination_dir) 46 if os.path.isdir(item): #如果差异路径为目录且不存在,则备份目录中创建 47 if not os.path.exists(destination_dir): 48 os.makedirs(destination_dir) 49 createdir_bool = True #再次调用compareme函数标记 50 51 ##对应第三个步骤 52 if createdir_bool: #重新调用compareme函数,重新遍历新创建目录的内容 53 destination_files = [] 54 source_files = [] 55 source_files = compare_me(dir1, dir2) #调用compareme函数 56 for item in source_files: #获取源目录差异路径清单,对应替换成备份目录 57 destination_dir = re.sub(dir1, dir2, item) 58 destination_files.append(destination_dir) 59 60 ##对应第四个步骤 61 print "update item: " 62 print source_files #输出更新项列表清单 63 copy_pair = zip(source_files, destination_files) #将源目录与备份目录文件清单拆分成元祖 64 print "copy_pair is %s" % copy_pair 65 for item in copy_pair: 66 print "item is %s, %s" % (item[0], item[1]) 67 if os.path.isfile(item[0]): #判断是否为文件,是则进行复制操作 68 shutil.copyfile(item[0], item[1]) 69 70 if __name__ == '__main__': 71 main()