别再手动比对文件啦,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() 类对两个字符串进行比较,另外 difflibSuquenceMatcher() 类支持任意类型序列的比较,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 的标准库已经自带了满足此需求的模块 filecmpfilecmp 可以实现文件、目录、遍历子目录的差异对比功能。比如报告中输出目标比原始多出的文件或子目录,即使文件同名也会判断是否为同一个文件(内容级对比)等,Python2.3 或更高版本默认自带 filecmp 模块,无需额外安装。官方文档:https://docs.python.org/3/library/filecmp.htmlfilecmp 提供了三个操作方法,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 提供了三个输出报告的方法:

  1. report():Print (to sys.stdout) a comparison between a and b.
  2. report_partial_closure():Print a comparison between a and b and common immediate subdirectories.
  3. 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.

  1. left:The directory a. 左目录,如类定义中的 a
  2. right:The directory b. 右目录,如类定义中的 b
  3. left_list:Files and subdirectories in a, filtered by hide and ignore. 左目录中的文件及目录列表
  4. right_list:Files and subdirectories in b, filtered by hide and ignore. 右目录中的文件及目录列表
  5. common:Files and subdirectories in both a and b. 两边目录共同存在的文件或目录
  6. left_only:Files and subdirectories only in a. 只在左目录中的文件或目录
  7. right_only:Files and subdirectories only in b. 只在右目录中的文件或目录
  8. common_dirs:Subdirectories in both a and b. 两边目录都存在的子目录
  9. common_files:Files in both a and b. 两边目录都存在的子文件
  10. 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()记录的错误)
  11. same_files:Files which are identical in both a and b, using the class’s file comparison operator. 匹配相同的文件
  12. diff_files:Files which are in both a and b, whose contents differ according to the class’s file comparison operator. 不匹配的文件
  13. funny_files:Files which are in both a and b, but could not be compared. 两边目录中都存在,但无法比较的文件
  14. 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 让你轻松实现文件内容以及目录对比!!!的主要内容,如果未能解决你的问题,请参考以下文章

Linux下9种优秀的代码比对工具推荐

千万别再学Python了?Python没用了?马上就要被淘汰啦?

千万别再学Python了?Python没用了?马上就要被淘汰啦?

INspiring | 别再为错过各类国民抽奖遗憾啦,你还有机会成为RBAC最IN的锦鲤!

tempfile:让你 Python 代码轻松无痕的运行

让你轻松实现对PDF文件的编辑修改