别再手动比对文件啦,Python 让你轻松实现文件内容以及目录对比!!!
Posted Amo Xiang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了别再手动比对文件啦,Python 让你轻松实现文件内容以及目录对比!!!相关的知识,希望对你有一定的参考价值。
问题引入:有这样的需求,在平时批改作业的时候,学生将源代码文件提交给我之后,我每次都要将源代码打开,逐一核对,文件数量一多就显得非常耗时且麻烦,有没有什么更快捷的方式呢?答案:有的。让学生按照我指定的格式,填写答案,然后使用 Python 自动实现文件内容的比较!接下来就去给大家讲讲文件内容差异对比以及文件目录的比较方法。
一、文件内容差异对比方法
通过 difflib 模块实现文件内容差异对比。difflib 作为 Python 的标准库模块,无需安装,作用是对比文件之间的差异,且支持输出可读性比较强的 html 文档,与 Linux 下的 diff 命令相似。我们可以使用 difflib 对比代码、配置文件的差别,在版本控制方面是非常有用。官方文档:https://docs.python.org/3/library/difflib.html。
1.1 两个字符串的差异对比
本示例通过使用 difflib 模块实现两个字符串的差异对比,然后以版本控制风格进行输出。示例代码如下:
import difflib
from pprint import pprint
text1_lines = ''' 1. Beautiful is better than ugly.
2. Explicit is better than implicit.
3. Simple is better than complex.
4. Complex is better than complicated.'''.splitlines(keepends=True)
# 以行进行分割,以便进行对比
text2_lines = ''' 1. Beautiful is better than ugly.
3. Simple is better than complex.
4. Complicated is better than complex.
5. Flat is better than nested.'''.splitlines(keepends=True)
d = difflib.Differ() # 创建Differ()对象
result = list(d.compare(text1_lines, text2_lines)) # 采用compare方法对字符串进行比较
pprint(result)
被示例采用 Differ() 类对两个字符串进行比较,另外 difflib 的 SuquenceMatcher() 类支持任意类型序列的比较,HtmlDiff() 类支持将比较结果输出为 HTML 格式,示例运行结果如下:
Each line of a Differ delta begins with a two-letter code:
1.2 生成美观的对比HTML格式文档
示例代码如下:
import difflib
text1_lines = ''' 1. Beautiful is better than ugly.
2. Explicit is better than implicit.
3. Simple is better than complex.
4. Complex is better than complicated.'''.splitlines(keepends=True)
# 以行进行分割,以便进行对比
text2_lines = ''' 1. Beautiful is better than ugly.
3. Simple is better than complex.
4. Complicated is better than complex.
5. Flat is better than nested.'''.splitlines(keepends=True)
d = difflib.HtmlDiff() # 创建HtmlDiffer()对象
with open("test.html", "w") as file:
# 采用make_file方法对字符串进行比较 并写入到html文件中
file.write(d.make_file(text1_lines, text2_lines))
使用浏览器打开 test.html 文件,如下图所示,HTML 文档包括了行号、差异标志、图例等信息,可读性增强了很多。
二、文件目录差异对比方法
当我们进行代码审计或校验备份结果时,往往需要检查原始与目标的文件一致性,Python 的标准库已经自带了满足此需求的模块 filecmp。filecmp 可以实现文件、目录、遍历子目录的差异对比功能。比如报告中输出目标比原始多出的文件或子目录,即使文件同名也会判断是否为同一个文件(内容级对比)等,Python2.3 或更高版本默认自带 filecmp 模块,无需额外安装。官方文档:https://docs.python.org/3/library/filecmp.html。 filecmp 提供了三个操作方法,cmp(单文件对比) 如下:
filecmp.cmp(f1, f2, shallow=True)
Compare the files named f1 and f2, returning True if they seem equal, False otherwise.
cmpfiles(多文件对比) 如下:
filecmp.cmpfiles(dir1, dir2, common, shallow=True)
Compare the files in the two directories dir1 and dir2 whose names are given by common.
Returns three lists of file names: match, mismatch, errors.
For example, cmpfiles('a', 'b', ['c', 'd/e']) will compare a/c with b/c and a/d/e with b/d/e.
'c' and 'd/e' will each be in one of the three returned lists.
dircmp(目录对比) 如下:
class filecmp.dircmp(a, b, ignore=None, hide=None)
Construct a new directory comparison object, to compare the directories a and b.
ignore is a list of names to ignore, and defaults to filecmp.DEFAULT_IGNORES.
hide is a list of names to hide, and defaults to [os.curdir, os.pardir].
2.1 单文件对比
单文件对比:采用 filecmp.cmp(f1, f2, shallow=True) 方法,比较文件名为 f1 和 f2 的文件,相同返回 True,不相同返回 False,shallow 默认为 True,意思是只根据 os.stat() 方法返回的文件基本信息进行对比,比如最后访问时间、修改时间、状态改变时间等,会忽略文件内容的对比。当 shallow 为 False 时,则 os.stat() 与文件内容同时进行校验。文件内容如下:
完整示例代码如下:
import filecmp
print(filecmp.cmp("test1.txt", "test2.txt")) # False
print(filecmp.cmp("test2.txt", "test3.txt")) # True
2.2 多文件对比
多文件对比:采用 filecmp.cmpfiles(dir1, dir2, common, shallow=True) 方法,对比 dir1 与 dir2 目录给定的文件清单。该方法返回文件名的三个列表,分别为匹配、不匹配、错误。匹配为包含匹配的文件的列表,不匹配反之,错误列表包含了目录不存在文件、不具备读权限或其他原因导致的不能比较的文件清单。目录文件列表如下:
完整示例代码如下:
import filecmp
print(filecmp.cmpfiles('one', 'two', ['test1.txt', 'test2.txt', 'test3.txt', 'test4.txt', 'test5.txt']))
2.3 目录对比
通过 filecmp.dircmp(a, b, ignore=None, hide=None) 类创建一个目录比较对象,其中 a 和 b 是参加比较的目录名。ignore 代表文件名忽略的列表,hide 代表隐藏的列表,默认 [os.curdir, os.pardir]
。dircmp 类可以获得目录比较的详细信息,如只有在 a 目录中包括的文件、a 与 b 都存在的子目录、匹配的文件等,同时支持递归。dircmp 提供了三个输出报告的方法:
- report():Print (to sys.stdout) a comparison between a and b.
- report_partial_closure():Print a comparison between a and b and common immediate subdirectories.
- report_full_closure():Print a comparison between a and b and common subdirectories (recursively).
The dircmp class offers a number of interesting attributes that may be used to get various bits of information about the directory trees being compared.
- left:The directory a. 左目录,如类定义中的 a
- right:The directory b. 右目录,如类定义中的 b
- left_list:Files and subdirectories in a, filtered by hide and ignore. 左目录中的文件及目录列表
- right_list:Files and subdirectories in b, filtered by hide and ignore. 右目录中的文件及目录列表
- common:Files and subdirectories in both a and b. 两边目录共同存在的文件或目录
- left_only:Files and subdirectories only in a. 只在左目录中的文件或目录
- right_only:Files and subdirectories only in b. 只在右目录中的文件或目录
- common_dirs:Subdirectories in both a and b. 两边目录都存在的子目录
- common_files:Files in both a and b. 两边目录都存在的子文件
- common_funny:Names in both a and b, such that the type differs between the directories, or names for which os.stat() reports an error. 两边目录都存在的子目录(不同目录类型或os.stat()记录的错误)
- same_files:Files which are identical in both a and b, using the class’s file comparison operator. 匹配相同的文件
- diff_files:Files which are in both a and b, whose contents differ according to the class’s file comparison operator. 不匹配的文件
- funny_files:Files which are in both a and b, but could not be compared. 两边目录中都存在,但无法比较的文件
- subdirs:A dictionary mapping names in common_dirs to dircmp objects. 将common_dirs目录映射到新的dircmp对象,格式为字典类型
示例:对比 one 与 two 的目录差异。通过调用 dircmp() 方法实现目录差异对比功能,同时输出目录对比对象所有属性信息。代码如下:
import filecmp
cmp = filecmp.dircmp("one", "two")
print(cmp.report())
程序运行结果如下图所示:
以上是关于别再手动比对文件啦,Python 让你轻松实现文件内容以及目录对比!!!的主要内容,如果未能解决你的问题,请参考以下文章
千万别再学Python了?Python没用了?马上就要被淘汰啦?
千万别再学Python了?Python没用了?马上就要被淘汰啦?