前情提示: 测试代码中,右尖括号(>
)表示命令行中输入的命令; 单独一行并以井字符(#
)开头的为输出内容; 库的导入仅在本文的第一个测试代码中展现,其他代码块均省略库的导入代码。
- 系统类型:
Windows 10
- python 版本:
Python 3.9.0
filecmp
模块可以用于文件与文件之间或目录与目录之间的比较。并且可以通过设置参数来选取多种不同用时和不同准确性的方案。
filecmp
模块在进行文件或目录对比时,最终仅能返回是否相等这一结果。某些场景需要更加详细的结果说明,可以使用 difflib
标准库。
快捷函数
filecmp.cmp(f1, f2, shallow=True)
参数:
f1, f2: 要进行比较的两个文件
shallow: 关键字参数, 参数值为布尔值, 默认为 True;
如果为 True, 则判断两文件需要具有相同的 os.stat() 签名才会认为是相等的;
如果为 False, 则比较两文件的内容;
返回值:
布尔值, 两个文件是否相等
比较 f1
和 f2
的文件,如果它们似乎相等则返回 True
,否则返回 False
。在官方文档中用上了 '似乎' 一词,这让人感觉有什么隐秘的信息文档上没有表达出来。
import filecmp
import os
'''本次测试代码中存在 4 个待对比文件, 其中 文件1 与 文件2 内容不同, 文件3 与 文件4 内容相同'''
print(os.stat('文件1'))
print(os.stat('文件2'))
print(filecmp.cmp('文件1', '文件2', shallow=True))
print(filecmp.cmp('文件1', '文件2', shallow=False))
# os.stat_result(st_mode=33206, st_ino=1407374883609775, st_dev=3098197482, st_nlink=1, st_uid=0, st_gid=0, st_size=4, st_atime=1611109066, st_mtime=1611109066, st_ctime=1611043715)
# os.stat_result(st_mode=33206, st_ino=1688849860320432, st_dev=3098197482, st_nlink=1, st_uid=0, st_gid=0, st_size=4, st_atime=1611045689, st_mtime=1611045689, st_ctime=1611043722)
# True
# True
当比较内容相同的 文件1
与 文件2
时,参数 shallow
无论设置为 True
还是 False
结果都是 True
。按照文档所述,文件1
和 文件2
的 os.stat()
是不相同的,当参数 shallow
设置为 True
时,根据两个文件的 os.stat()
最终应该得到 False
。为什么实际运行和文档描述不同呢?
查阅一些资料后,找到了一个比较合理的解释,当参数 shallow
设置为 True
,那么 os.stat()
相同的会直接被视为相等,当两个文件的 os.stat()
不同时,依旧会对比文件中的内容。
另外,此函数会缓存比较结果,在下次比较时直接返回缓存结果。如果文件的 os.stat()
变化了,也就是文件被修改了,缓存自动失效。缓存也能用下文中的 filecmp.clear_cache()
函数清除。
filecmp.cmpfiles(dir1, dir2, common, shallow=True)
参数:
dir1, dir2: 目录
common: 需要对比的文件名列表
shallow: 关键字参数, 参数值为布尔值, 默认为 True;
如果为 True, 则判断两文件需要具有相同的 os.stat() 签名才会认为是相等的;
如果为 False, 则比较两文件的内容;
返回值:
元组, 包含三个类型为列表的元素.
比较两个目录下的指定文件,返回对比结果,返回值是包含三个类型为列表的元素的元组。
'''
文件目录如下, 其中, 两个目录内的 文件a 内容相同, 文件c 内容不同
- 目录1
- 文件a
- 目录b
- 文件c
- 文件d
- 目录2
- 文件a
- 目录b
- 文件c
'''
'''对比两目录下的文件'''
print(filecmp.cmpfiles('目录1', '目录2', ['文件a', '目录b/文件c', '文件d']))
# (['文件a'], ['目录b/文件c'], ['文件d'])
参数 common
列举要对比的文件名,分别对比两个目录下的同名文件,如果两个文件相同,则加入返回值的第一个元素内; 如果两个文件内容不同,则加入返回值的第二个元素内; 如果文件无权限读取或者文件在任一目录内缺失,则加入返回值的第三个元素内;
参数 shallow
与上文中 filecmp.cmp()
函数意义相同。
filecmp.clear_cache()
清除 filecmp
缓存。一般情况下,文件修改后,文件的 os.stat()
自然会改变,缓存也会自动失效。但是如果文件被过快的修改,以至于超过底层文件系统记录修改时间的精度时,那么此后的文件对比将可能会出现问题,此函数就是为了解决这个问题。
但是,这种文件过快的修改不知道怎样测试出来? 大家有知道的吗?
dircmp 类
class filecmp.dircmp(a, b, ignore=None, hide=None)
参数:
a, b: 目录
ignore: 关键字参数, 需要忽略的文件名列表, 默认为 filecmp.DEFAULT_IGNORES
hide: 关键字参数, 需要隐藏的文件名列表, 默认为 [os.curdir, os.pardir]
创建一个用于比较两个目录的目录比较对象。参数 ignore
可忽略指定的文件名,hide
可隐藏指定的文件名。
print(filecmp.DEFAULT_IGNORES)
# ['RCS', 'CVS', 'tags', '.git', '.hg', '.bzr', '_darcs', '__pycache__']
print(os.curdir)
# .
print(os.pardir)
# ..
dircmp
类中有许多属性,这里使用测试代码直接展示:
dircmp_test = filecmp.dircmp('目录1', '目录2')
'''第一个(相对左边)参数, 也是第一个目录的名称'''
print(dircmp_test.left)
# 目录1
'''第二个(相对右边)参数, 也是第二个目录的名称'''
print(dircmp_test.right)
# 目录2
'''经参数 hide 与参数 ignore 过滤后, 第一个目录内的所有文件与子目录'''
print(dircmp_test.left_list)
# ['文件a', '文件d', '目录b']
'''经参数 hide 与参数 ignore 过滤后, 第二个目录内的所有文件与子目录'''
print(dircmp_test.right_list)
# ['文件a', '目录b']
'''同时存在两个目录下的文件与子目录'''
print(dircmp_test.common)
# ['文件a', '目录b']
'''仅存在第一个目录下的文件与子目录'''
print(dircmp_test.left_only)
# ['文件d']
'''仅存在第二个目录下的文件与子目录'''
print(dircmp_test.right_only)
# []
'''同时存在两个目录下的子目录'''
print(dircmp_test.common_dirs)
# ['目录b']
'''将 common_dirs 属性值映射为 dircmp 对象的字典'''
print(dircmp_test.subdirs)
# {'目录b': }
'''同时存在两个目录下的文件'''
print(dircmp_test.common_files)
# ['文件a']
'''在两个目录中类型不同的名字,或者那些 os.stat() 报告错误的名字'''
print(dircmp_test.common_funny)
# []
'''在两个目录下, 使用类的比较操作符相同的文件'''
print(dircmp_test.same_files)
# ['文件a']
'''在两个目录下, 使用类的比较操作符不同的文件'''
print(dircmp_test.diff_files)
# []
'''无法比较的文件'''
print(dircmp_test.funny_files)
# []
dircmp
类也提供了一些用于打印信息的方法,同样,直接在测试用例中展示:
'''将 a 与 b 之间的比较打印'''
dircmp_test.report()
# diff 目录1 目录2
# Only in 目录1 : ['文件d']
# Identical files : ['文件a']
# Common subdirectories : ['目录b']
'''打印 a 与 b 及共同直接子目录的比较结果'''
dircmp_test.report_partial_closure()
# diff 目录1 目录2
# Only in 目录1 : ['文件d']
# Identical files : ['文件a']
# Common subdirectories : ['目录b']
#
# diff 目录1\目录b 目录2\目录b
# Differing files : ['文件c']
'''打印 a 与 b 及共同子目录比较结果(递归地)'''
dircmp_test.report_full_closure()
# diff 目录1 目录2
# Only in 目录1 : ['文件d']
# Identical files : ['文件a']
# Common subdirectories : ['目录b']
#
# diff 目录1\目录b 目录2\目录b
# Differing files : ['文件c']
公众号 : 「python杂货铺」,专注于 python 语言及其相关知识。发掘更多原创文章,期待您的关注。