且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

文件与目录差异对比方法

更新时间:2022-08-18 23:14:21

环境:

Python 2.6.6

linux系统


用到的模块:filecmp

filecmp提供了:单文件对比,多文件对比,目录对比


单文件对比:采用filecmp.cmp(f1,f2[,shallow])方法,比较文件名为f1和f2的文件的内容,相同返回True,不相同返回False,shallow默认是True,意思是只根据os.stat()方法返回的文件基本信息进行对比,比如最后访问时间、修改时间、状态改变时间等,会忽略文件内容的对比。当shallow为False时,则os.stat()与文件内容同时进行校验。


例子:

1
2
3
4
5
>>> import filecmp
>>> filecmp.cmp("/root/dir1/f1","/root/dir2/f1")
True
>>> filecmp.cmp("/root/dir1/f1","/root/dir2/f5")
False

多文件对比:采用filecmp.cmpfiles(dir1, dir2, common[, shallow])方法,对比dir1与dir2目录给定的文件清单。该方法返回文件名的三个列表,分别为匹配、不匹配、错误。匹配为包含匹配的文件的列表,不匹配反之,错误列表包括了目录不存在文件、不具备读权限或其他原因导致的不能比较的文件清单。

例子:

先建立一些文件:

文件与目录差异对比方法

代码:

1
2
>>> filecmp.cmpfiles("/root/dir1","/root/dir2",['f1','f2','f3','f4','f5'])
(['f1''f2''f3''f4'], [], ['f5'])


目录对比:通过dircmp(a, b[, ignore[, hide]])类创建一个目录比较对象,其中a和b是参加比较的目录名。ignore代表文件名忽略的列表,并默认为['RCS', 'CVS', 'tags'];hide代表隐藏的列表,默认为[os.curdir,os.pardir]。dircmp类可以获得目录比较的详细信息,如只有在a目录中包括的文件、a与b都存在的子目录、匹配的文件等,同时支持递归。


例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/usr/bin/env python
#-*—coding:utf-8-*-
#2017,9,7
 
import filecmp
 
= "/root/dir1" #定义左目录
= "/root/dir2" #定义右目录
 
dirobj = filecmp.dircmp(a,b,['1.py']) #目录比较,忽略1.py文件。
 
dirobj.report() #比较当前指定目录中的内容
dirobj.report_full_closure() #递归比较所有指定目录的内容
dirobj.report_partial_closure() #比较当前指定目录以及第一级目录中的内容
 
print "_"*50
print "left_list:" + str(dirobj.left_list) #左目录
print "_"*50
print "right_list:"+str(dirobj.right_list) #右目录
print "_"*50
print "commom:"+str(dirobj.common) #两边共同存在的目录
print "_"*50
print "left_only:"+str(dirobj.left_only) #只在左目录中的文件或者目录
print "_"*50
print "right_only:"+str(dirobj.right_only)  #只在右目录中的文件或者目录
print "_"*50
print "common_dirs:"+str(dirobj.common_dirs)#两边目录都存在的子目录
print "_"*50
print "common_files:"+str(dirobj.common_files) #两边目录都存在的文件
print "_"*50
print "common_funny:"+str(dirobj.common_funny) #两边目录都存在的目录
print "_"*50
print "same_files:"+str(dirobj.same_files) #匹配相同的文件
print "_"*50
print "diff_files:" + str(dirobj.diff_files) #不匹配的文件
print "_"*50
print "funny_files:" + str(dirobj.diff_files) #两边目录中都存在,但是无法比较的文件

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
diff /root/dir1 /root/dir2
Only in /root/dir2 : ['f5']
Identical files : ['f1''f2''f3''f4']
diff /root/dir1 /root/dir2
Only in /root/dir2 : ['f5']
Identical files : ['f1''f2''f3''f4']
diff /root/dir1 /root/dir2
Only in /root/dir2 : ['f5']
Identical files : ['f1''f2''f3''f4']
__________________________________________________
left_list:['f1''f2''f3''f4']
__________________________________________________
right_list:['f1''f2''f3''f4''f5']
__________________________________________________
commom:['f1''f2''f3''f4']
__________________________________________________
left_only:[]
__________________________________________________
right_only:['f5']
__________________________________________________
common_dirs:[]
__________________________________________________
common_files:['f1''f2''f3''f4']
__________________________________________________
common_funny:[]
__________________________________________________
same_files:['f1''f2''f3''f4']
__________________________________________________
diff_files:[]
__________________________________________________
funny_files:[]


实践:效验源与备份目录差异

源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#!/usr/bin/env python
#coding:utf-8
#2017,9,7
 
import os
import 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 in only_in_one]
        [holderlist.append(os.path.abspath(os.path.join(dir1,x))) for in diff_in_one]
        if len(dircomp.common_dirs) > 0:
                for item in dircomp.common_dirs:
        return holderlist
 
 
def main():
        if len(sys.argv) > 2:
                dir1 = sys.argv[1]
                dir2 = sys.argv[2]
        else:
                print "usage:",sys.argv[0],"datadir backupdir"
                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) #将源目录差异路径清单对应替换成备份目录
                destination_files.append(destination_dir)
                if os.path.isdir(item):           #如果差异路径为目录且不存在,则在备份目录中创建
                        if not os.path.exists(destination_dir):
                                os.makedirs(destination_dir)
                                createdir_bool = True #再一次调用compareme函数标记
        if createdir_bool:
                destination_files = []
                source_files=[]
                source_files=compareme(dir1,dir2)
                for item in source_files:
                        destination_dir = re.sub(dir1,dir2,item)
                        destination_files.append(destination_dir)
        print "updata 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()

执行结果:

文件与目录差异对比方法


总结\注意\拓展:


总结:

本次学习不仅学会了文件备份的效验,而且学习到了一个语法:

1
2
3
4
 [holderlist.append(os.path.abspath(os.path.join(dir1,x))) for in only_in_one]
 #正常写法
 for in only_in_one:
     holderlist.append(os.path.abspath(os.path.join(dir1,x)))

注意:

在写程序的时候一定要注意缩进,不然容易报错,我在写下面这句的时候就老报语法错误,做后让别人打一遍,我复制一下才成功:

1
return holderlist


拓展:

re.sub是re模块重要的组成部分,并且功能也非常强大,主要功能实现正则的替换

re.sub定义: 
sub(pattern, repl, string, count=0, flags=0)


解释:

pattern:为表示正则中的模式字符串, 
repl为replacement,被替换的内容,repl可以是字符串,也可以是函数。 
string为正则表达式匹配的内容。 
count:由于正则表达式匹配到的结果是多个,使用count来限定替换的个数(顺序为从左向右),默认值为0,替换所有的匹配到的结果。 
flag是匹配模式,可以使用按位或’|’表示同时生效,也可以在正则表达式字符串中指定。

例子:

1
2
3
>>>import re
>>>re.sub(r'\w+','10',"ji 43 af,geq",2,flags=re.I)
>>>'10 10 af,geq'


shutil模块:

详情参考:http://blog.csdn.net/xmnathan/article/details/36217631



参考链接1:https://book.2cto.com/201411/48243.html

参考链接2:http://blog.csdn.net/hjxzt1/article/details/73741507

参考资料1:百度知道

参考资料2:网络资源

参考资料3:《Python自动化运维技术与***实践》-刘天斯 著


文件与目录差异对比方法



本文转自 天道酬勤VIP 51CTO博客,原文链接:http://blog.51cto.com/tdcqvip/1963827