文件内容差异对比
示例1:difflib模块——两个字符串的差异对比
通过使用difflib模块实现两个字符串的差异对比,然后以版本控制风格进行输出。
1 #!/usr/bin/evn python 2 # --*-- coding: utf-8 --*-- 3 # Auther : Liu WeiDong 4 import difflib 5 6 text1 = '''test1: #字符串1 7 This module provides classes. 8 including HTML and context. 9 difflib document7.4 10 add string 11 ''' 12 text1_lines = text1.splitlines() #以行进行分隔 13 14 text2 = '''test2: #字符串2 15 This module provides classes. 16 including HTML and context. 17 difflib document7.5 18 ''' 19 20 text2_lines = text2.splitlines() 21 22 d = difflib.Differ() #创建Differ()对象 23 24 diff = d.compare(text1_lines,text2_lines) 采用compare方法对字符串进行比较 25 print('\n'.join(list(diff)))
可以将以上代码换行html格式,将如上脚本运行python diff.py > diff.html,在使用浏览器打开diff.html文件
1 #!/usr/bin/evn python 2 # --*-- coding: utf-8 --*-- 3 # Auther : Liu WeiDong 4 import difflib 5 6 text1 = '''test1: #字符串1 7 This module provides classes. 8 including HTML and context. 9 difflib document7.4 10 add string 11 ''' 12 text1_lines = text1.splitlines() #以行进行分隔 13 14 text2 = '''test2: #字符串2 15 This module provides classes. 16 including HTML and context. 17 difflib document7.5 18 ''' 19 20 text2_lines = text2.splitlines() 21 22 # d = difflib.Differ() #创建Differ()对象 23 # 24 # diff = d.compare(text1_lines,text2_lines) 采用compare方法对字符串进行比较 25 # print('\n'.join(list(diff))) 26 27 d = difflib.HtmlDiff() 28 print(d.make_file(text1_lines,text2_lines))
示例2:difflib模块——对比nginx配置文件
当我们维护多个Nginx配置时,时常会对比不同版本配置文件的差异,使运维人员更加清晰的了解不同版本迭代后的更新项,实现的思路是读取两个需对比的配置文件,再以换行符作为分隔符,调用difflib.HtmlDiff()生成HTML格式的差异文档。
1 #!/usr/bin/evn python 2 # --*-- coding: utf-8 --*-- 3 # Auther : Liu WeiDong 4 5 6 import difflib 7 import sys 8 9 #首先判断脚本是否传了正确参数 10 11 try: 12 textfile1 = sys.argv[1] 13 textfile2 = sys.argv[2] 14 except Exception as e: 15 print("Error" + str(e)) 16 print("Usage: simple3.py filename1 filename2") 17 sys.exit() 18 19 #定义一个读取文件的函数,以换行符进行分隔 20 def readfile(filename): 21 try: 22 with open(filename,'rb') as fin: 23 text = fin.read().splitlines() 24 return text 25 except IOError as error: 26 print("Read file Error:" + str(error)) 27 sys.exit() 28 29 text1_lines = readfile(textfile1) 30 text2_lines = readfile(textfile2) 31 32 d = difflib.HtmlDiff() 33 print(d.make_file(text1_lines,text2_lines))
运行代码:
# python simple3.py nginx.v1.conf nginx.v2.conf > diff.html
示例三:filecmp模块——文件与目录差异对比
模块常用方法说明:fileemp提供了三个操作方法,分别为cmp(单文件对比)、cmpfile(多文件对比)、dircmp(目录对比),下面逐一进行介绍:
- 单文件对比,采用filecmp.cmp (f1,f2[,shallow])方法,比较文件名为f1和f2的文件,相同返回True,不相同返回False,shallow默认为True。
- 多文件对比,采用filecmp.cmpfiles(dir1,dir2,common[,shallow])方法,对比dir1与dir2目录给定的文件清单。该方法返回文件名的三个列表,分别为匹配,不匹配,错误。匹配为包含匹配的文件的列表,不匹配反之,错误列表包括了目录不存在的文件、不具备读权限或其他原因导致的不能比较的文件清单。
- 目录对比,采用filecmp.dircmp(a,b[,ignore[,hide]])类创建一个目录比较对象,其中a和b是参加比较的目录名。ignore代表文件名忽略的列表,并默认为['RCS','CVS','tags'];hide代表隐藏的列表,默认为[os.curdir(当前目录),os.pardir(上一层目录)],dircmp类可以获得目录比较的详细信息,如只有在a目录中包括的文件、a与b都存在的子目录、匹配的文件等,同时支持递归。
示例四:校验源与备份目录差异
有时候我们无法确认备份目录与源目录文件是否一致,包括源目录中的新文件或目录、更新文件或目录有无成功同步,定期进行校验,没有成功则希望有针对性地进行补备份。
如下示例使用了filecmp模块的left_only、diff_files方法递归获取源目录的更新项,在通过shutil.copyfile、os.makedirs方法对更新项进行复制,最终保持一致状态。代码如下:
1 #!/usr/bin/evn python 2 # --*-- coding: utf-8 --*-- 3 # Auther : Liu WeiDong 4 5 import os,sys 6 import filecmp 7 import re 8 import shutil 9 10 holderlist = [] 11 12 # 定义一个函数,判断两个目录差异 13 def compareme(dir1,dir2): 14 dircomp = filecmp.dircmp(dir1,dir2) 15 only_in_leftdir = dircomp.left_only #返回一个只在dir1中的文件或目录列表 16 diff_in_leftdir = dircomp.diff_files #显示返回两个目录中相同文件名,内容不同 17 #dirpath = os.path.abspath(dir1) # 定义源文件的绝对路径 18 19 #将更新的文件名或目录追加到holderlist 20 for i in only_in_leftdir: 21 holderlist.append(os.path.abspath(os.path.join(dir1,i))) 22 23 for i in diff_in_leftdir: 24 holderlist.append(os.path.abspath(os.path.join(dir1,i))) 25 26 #判断是否存在相同子目录,以便递归 27 if len(dircomp.common_dirs) > 0: 28 for i in dircomp.common_dirs: 29 compareme(os.path.abspath(os.path.join(dir1,i)),os.path.abspath(os.path.join(dir2,i))) 30 return holderlist 31 32 def main(): 33 if len(sys.argv) > 2: #判断脚本参数个数是否大于2 34 dir1 = sys.argv[1] 35 dir2 = sys.argv[2] 36 else: 37 print("Usage: ",sys.argv[0]," datadir backupdir") 38 sys.exit() 39 40 #调用compareme函数,对传入的两个目录进行对比 41 different_file = compareme(dir1,dir2) 42 dir1 = os.path.abspath(dir1) 43 44 if not dir2.endswith("/"): 45 dir2 = dir2 + '/' 46 dir2 = os.path.abspath(dir2) 47 destination_files = [] 48 creatdir_bool = False 49 50 for item in different_file: #遍历返回的差异文件或目录列表 51 destination_dir = re.sub(dir1,dir2,item) #将源目录差异路径清单对应替换成备份目录 52 destination_files.append(destination_dir) # 备份目录内容更新到定义的destination_files列表中 53 if os.path.isdir(item): # 如果差异路径为目录且不存在,则在备份目录中创建 54 if not os.path.exists(destination_dir): 55 os.makedirs(destination_dir) 56 creatdir_bool = True 57 58 if creatdir_bool: #重新调用compareme函数,重新遍历创建目录的内容 59 destination_files = [] 60 different_file = [] 61 different_file = compareme(dir1,dir2) 62 for item in different_file: 63 destination_dir = re.sub(dir1,dir2,item) 64 destination_files.append(destination_dir) 65 66 print("update item:") 67 print(destination_files) 68 copy_pair = zip(different_file,destination_files) 69 for item in copy_pair: 70 if os.path.isfile(item[0]): 71 shutil.copyfile(item[0],item[1]) 72 73 if __name__ == '__main__': 74 main()
不积跬步,无以至千里;不积小流,无以成江海。