13. python difflib和filecmp文本比较模块

 


13.python difflib和filecmp文本比较模块

difflib 与 filecmp 的区别:

特点 difflib filecmp
功能定位 详细比较文本内容,生成差异报告 快速判断文件或目录是否相同
输出结果 详细差异报告(支持 HTML 格式) 布尔值或文件列表(相同、不同、错误)
性能 逐行比较,性能较低 通过元数据快速比较,性能较高
适用场景 文本文件的详细差异分析 文件和目录的快速比较
使用复杂度 较高,需要处理文本内容 较低,直接比较文件或目录

difflib

实例1:两个字符串的差异对比

#!/usr/bin/python3
#_*_coding:utf-8_*_


import difflib

# 定义两段字符串
text1 = """Hello, world!
This is the first string.
Line 3 is unique to text1.
"""

text2 = """Hello, world!
This is the second string.
Line 3 is unique to text2.
"""

# 将字符串按行分割为列表
lines1 = text1.splitlines()
lines2 = text2.splitlines()

# 使用 difflib.unified_diff 生成差异报告
# diff = difflib.unified_diff(lines1, lines2, fromfile="text1", tofile="text2")

#使用compare() 输出差异对比
d = difflib.Differ()
diff = d.compare(lines1,lines2)

# 打印差异
print("\n".join(diff))

unified_diff输出:

compare输出:

符号及含义:

实例2:使用HTML格式美化对比

root@jiaxing:~/test-venv# cat test.py 
#!/usr/bin/python3
#_*_coding:utf-8_*_


import difflib

# 定义两段字符串
text1 = """Hello, world!
This is the first string.
Line 3 is unique to text1.
"""

text2 = """Hello, world!
This is the second string.
Line 3 is unique to text2.
"""

# 将字符串按行分割为列表
lines1 = text1.splitlines()
lines2 = text2.splitlines()

d = difflib.HtmlDiff()
print(d.make_file(lines1,lines2))
root@jiaxing:~/test-venv# 
root@jiaxing:~/test-venv# python3 test.py >/app/code/blog/index.html

html输出在浏览器中访问:

实例3:nginx文件对比

#!/usr/bin/python3
#_*_coding:utf-8_*_


import difflib
import sys


try:
    textfile1 = sys.argv[1] #第一个文件路径参数
    textfile2 = sys.argv[2] #第二个文件路径参数
except Exception as e:
    print(f"Error:{str(e)}")
    print("Usage: test.py filename1 filename2")
    sys.exit()

def readfile(filename):
    try:
        with open(filename,'r') as f:
            return f.readlines()
    except Exception as e:
        print(f"Read file Error:{str(e)}")
        sys.exit()	#退出脚本

def compare_file(textfile1,textfile2):
    text1_line1 = readfile(textfile1)   #readfile()函数获取分割后的字符串
    text2_line2 = readfile(textfile2)
    #实例化HtmlDiff
    d = difflib.HtmlDiff()
    result = d.make_file(text1_line1,text2_line2)
    return result

if __name__ == '__main__':
    result = compare_file(textfile1,textfile2)

    with open('/app/code/blog/index.html','w') as f:
        f.writelines(result)

输出:

filecmp

  • 当我们进行代码审计和校验备份结果时,往往需要检查原始与目标目录的文件是否一致性,那么python的标准库已经自带了满足此需求的模块filecmp。
  • filecmp可以实现文件、目录、遍历子目录的差异对比功能,即使文件同名也会对比其内容是否一致

常用方法说明

  • filecmp提供了三个方法:cmp(单文件对比)、cmpfiles(多文件对比)、dircmp(目录对比)

单文件对比:filecmp.cmp(f1,f2,shallow=True)

  • 如果f1和f2相同则返回True,不同返回False
  • shallow默认为True,只比较文件的元数据(如文件大小、修改时间等),而不检查文件的实际内容
  • shallow=False,则会进行“深度比较”,即不仅比较元数据,还会检查文件的实际内容
In [1]: import filecmp

In [2]: filecmp.cmp('./f1','./f2',shallow=True)
Out[2]: True

In [3]: filecmp.cmp('./f1','./f3',shallow=True)
Out[3]: False

In [4]: filecmp.cmp('./f1','./f3',shallow=False)
Out[4]: False

In [5]: filecmp.cmp('./f1','./f2',shallow=False)
Out[5]: True

多文件对比:filecmp.cmpfiles(f1,f2,shallow=True)

  • 该方法返回三个列表:分别为匹配、不匹配、错误
    • 匹配:两个目录下同时存在同名文件且内容也相同
    • 不匹配:两个目录下同时存在同名文件但内容不相同
    • 错误:两个目录下不同时存在的文件

示例:

	#两个目录下md5值对比
(test-venv) root@jiaxing:~/test-venv# md5sum dir1/*
1181c1834012245d785120e3505ed169  dir1/f1
348bd3ce10ec00ecc29d31ec97cd5839  dir1/f2
40b134ab8a3dee5dd9760a7805fd495c  dir1/f3
41d9737bc75ae8fa57b7a84a44fba01c  dir1/f5
(test-venv) root@jiaxing:~/test-venv# md5sum dir2/*
1181c1834012245d785120e3505ed169  dir2/f1
348bd3ce10ec00ecc29d31ec97cd5839  dir2/f2
23ebe88c0224f4f4fc0b608216e98735  dir2/f3
45a62d3d5d3e946250904697486591bc  dir2/f4

In [2]: filecmp.cmpfiles('dir1','dir2',['f1','f2','f3','f4','f5'])
Out[2]: (['f1', 'f2'], ['f3'], ['f4', 'f5'])

目录对比:filecmp.dircmp(a,b,[,ignore[,hide]])

  • 该方法是 filecmp 模块中用于比较两个目录的内容和结构的函数。它提供了一个方便的方式来递归比较两个目录中的文件和子目录,并生成详细的比较结果。

filecmp.dircmp()参数解释:

  • a:第一个目录的路径(字符串)。
  • b:第二个目录的路径(字符串)。
  • ignore:(可选)一个文件名列表,指定在比较时忽略的文件或目录名。
  • hide:(可选)一个文件名列表,指定在比较结果中隐藏的文件或目录名。

返回值:

filecmp.dircmp() 返回一个 dircmp 对象,该对象包含以下属性和方法:

  • left:第一个目录的路径。
  • right:第二个目录的路径。
  • left_list:第一个目录中的文件和子目录列表。
  • right_list:第二个目录中的文件和子目录列表。
  • common:两个目录中都存在的文件和子目录。
  • left_only:仅存在于第一个目录中的文件和子目录。
  • right_only:仅存在于第二个目录中的文件和子目录。
  • diff_files:两个目录中内容不同的文件。
  • same_files:两个目录中内容相同的文件。
  • report():打印比较结果的摘要。
  • report_full_closure():递归打印所有子目录的比较结果。

实例1:比较两个目录内容

(test-venv) root@jiaxing:~/test-venv# cat test.py 
#!/usr/bin/python3
#_*_coding:utf-8_*_
import filecmp


#比较两个目录
dircmp = filecmp.dircmp('dir1','dir2')

#打印计较结果
print("相同的文件:", dircmp.same_files)
print("不同的文件:", dircmp.diff_files)
print("仅存在于 dir1 的文件:", dircmp.left_only)
print("仅存在于 dir2 的文件:", dircmp.right_only)

#打印摘要报告
dircmp.report()

#递归打印所有子目录的比较结果
dircmp.report_full_closure()

(test-venv) root@jiaxing:~/test-venv# 
(test-venv) root@jiaxing:~/test-venv# python3 test.py 
相同的文件: ['f1', 'f2']
不同的文件: ['f3']
仅存在于 dir1 的文件: ['f5']
仅存在于 dir2 的文件: ['f4']
diff dir1 dir2
Only in dir1 : ['f5']
Only in dir2 : ['f4']
Identical files : ['f1', 'f2']
Differing files : ['f3']
diff dir1 dir2
Only in dir1 : ['f5']
Only in dir2 : ['f4']
Identical files : ['f1', 'f2']
Differing files : ['f3']

(test-venv) root@jiaxing:~/test-venv# tree dir1 dir2
dir1
├── f1
├── f2
├── f3
└── f5

dir2
├── f1
├── f2
├── f3
└── f4

实例2:比较两个目录内容

#!/usr/bin/python3
#_*_coding:utf-8_*_

import sys
import os
import filecmp


diff_files = [] #名称相同但不一致的文件(目录)列表
left_only = []  #第一个目录独有的文件(目录)列表
right_only = [] #第二个目录独有的文件(目录)列表

#从命令行获取要比较的目录路径
try:
    dir1 = sys.argv[1]
    dir2 = sys.argv[2]
except Exception as e:
    print(f"Error: {e}")
    print("使用方法:python3 test.py 目录1 目录2")
    sys.exit()

"""处理目录的比较结果"""
def cmp_result(dcmp):
    for item in dcmp.diff_files:
        diff_files.append(os.path.join(dcmp.left,item))
    for item in dcmp.left_only:
        left_only.append(os.path.join(dcmp.left,item))
    for item in dcmp.right_only:
        right_only.append(os.path.join(dcmp.right,item))
    for sub_dcmp in dcmp.subdirs.values():  #subdirs是一个字典
        cmp_result(sub_dcmp)    #递归处理子目录


if __name__ == "__main__":
    dcmp = filecmp.dircmp(dir1,dir2)
    cmp_result(dcmp)
    diff_count = len(diff_files)
    left_count = len(left_only)
    right_count = len(right_only)
    if (diff_count == 0 and left_count == 0 and right_count == 0):
        print("两个目录完全一致")
    else:
        print("目录比较分析结果:")
        print(dir1 + "目录中独有" + str(left_count) + "个文件:", left_only )
        print(dir2 + "目录中独有" + str(right_count) + "个文件:", right_only)
        print("名称相同但不一致的有" + str(diff_count) + "个文件", diff_files)
posted @   逃离这世界~  阅读(11)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
点击右上角即可分享
微信分享提示

目录导航