python standard library filecmp

python 标准库 filecmp

每日一词:

病毒

germs、bacteria 還是 viruses

Germ: 微生物

Bacterium: 這是「細菌」的意思,它是微小且單細胞的有機體。注意喔這個字的單數是 bacterium,複數要寫作 bacteria

Virus:病菌

茲卡病毒(Zika virus)、諾羅病毒(Norovirus)、愛滋病毒(Human Immunodeficiency Virus,縮寫即是 HIV)、輪狀病毒(Rotavirus)等。

继续学习关于文件操作的模块 filecmp

源代码

源代码: Lib/filecmp.py

filecmp 模块定义了用于比较文件及目录的函数,并且可以选取多种关于时间和准确性的折衷方案。对于文件的比较,另见 difflib 模块。

函数

filecmp 模块定义了如下函数:

  • filecmp.`cmp`(f1, f2, shallow=True)
  • filecmp.`cmpfiles`(dir1, dir2, common, shallow=True)
  • filecmp.`clear_cache`()

dircmp

class filecmp.`dircmp`(a, b, ignore=None, hide=None)

创建一个用于比较目录 ab 的新的目录比较对象。 ignore 是需要忽略的文件名列表,且默认为 filecmp.DEFAULT_IGNOREShide 是需要隐藏的文件名列表,且默认为 [os.curdir, os.pardir]

dircmp 类如 filecmp.cmp() 中所描述的那样对文件进行 shallow 比较。

dircmp 类提供以下方法:

  • report()

    ab 之间的比较打印(到 sys.stdout )。

  • report_partial_closure()

    打印 ab 及共同直接子目录的比较结果。

  • report_full_closure()

    打印 ab 及共同子目录比较结果(递归地)。

dircmp 类提供了一些有趣的属性,用以得到关于参与比较的目录树的各种信息。

需要注意,通过 __getattr__() 钩子,所有的属性将会惰性求值,因此如果只使用那些计算简便的属性,将不会有速度损失。

  • left

    目录 a

  • right

    目录 b

  • left_list

    hideignore 过滤,目录 a 中的文件与子目录。

  • right_list

    hideignore 过滤,目录 b 中的文件与子目录。

  • common

    同时存在于目录 ab 中的文件和子目录。

  • left_only

    仅在目录 a 中的文件和子目录。

  • right_only

    仅在目录 b 中的文件和子目录。

  • common_dirs

    同时存在于目录 ab 中的子目录。

  • common_files

    同时存在于目录 ab 中的文件。

  • common_funny

    在目录 ab 中类型不同的名字,或者那些 os.stat() 报告错误的名字。

  • same_files

    在目录 ab 中使用类的文件比较操作符相等的文件。

  • diff_files

    在目录 ab 中,根据类的文件比较操作符判定内容不等的文件。

  • funny_files

    在目录 ab 中无法比较的文件。

  • subdirs

    一个将 common_dirs 中名称映射为 dircmp 对象的字典。

filecmp.`DEFAULT_IGNORES`

下面是一个简单的例子,使用 subdirs 属性递归搜索两个目录以显示公共差异文件:

1
2
3
4
5
6
7
8
9
10
>>> from filecmp import dircmp
>>> def print_diff_files(dcmp):
... for name in dcmp.diff_files:
... print("diff_file %s found in %s and %s" % (name, dcmp.left,
... dcmp.right))
... for sub_dcmp in dcmp.subdirs.values():
... print_diff_files(sub_dcmp)
...
>>> dcmp = dircmp('dir1', 'dir2')
>>> print_diff_files(dcmp)

例子

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/python3
#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()
坚持原创技术分享,您的支持将鼓励我继续创作!