文件内容差异对比方法

介绍如何通过difflib模块实现文件内容差异对比。difflib作为Python的标准库模块无需安装,作用是对比文本之间的差异,且支持输出可读性比较强的HTML文档,与Linux下的 diff命令相似。我们可以使用difflib 对比代码、配置文件的差别,在版本控制方面是非常有用。

在这里插入图片描述

2.1.1 两个字符串的差异对比

  1. 传递文件内容,然后进行简单的行切割
  2. 创建differ函数
  3. 在differ对象的基础上,借助于compare方法将两个内容进行对比
  4. 结果以join的方式展示
import difflib

# 准备第一个文件
text1 = """text1:
This module provides classes and functions for comparing 
includes
add string
"""
# 准备第二个文件
text1_line = text1.splitlines()     # 以行进行分割,以便进行对比
text2 = """text2:
This module provides classes and functions for comparing 
includes add string
"""
text2_line = text2.splitlines()
# 创建differ对象
d = difflib.Differ() #创建Differ对象
# 使用compare方法比较内容
diff = d.compare(text2_line,text1_line)
print(diff)
#<generator object Differ.compare at 0x000002249D0A7C80>

# 拼接比较后的结果
print('\n'.join(list(diff)))
<generator object Differ.compare at 0x0000024ABEC97C10>
- text2:
?     ^

+ text1:
?     ^

  This module provides classes and functions for comparing 
- includes add string
+ includes
+ add string

在这里插入图片描述

2.1.2 生成美观的HTML格式文档

采用 HtmIDiff()类的 make_file() 方法就可以生成美观的HTML文档

HtmlDiff() 类的make_file()方法:生成美观的HTML文档

  1. 传递文件内容,然后进行简单的行切割
  2. 创建HtmlDiff函数
  3. 在HtmlDiff对象的基础上,借助于make_file()方法将两个内容进行对比
  4. 直接查看生成的文件
    效果:
    颜色
    统计
import difflib

# 准备第一个文件
text1 = """text1:
This module provides classes and functions for comparing 
includes
add string
"""
# 准备第二个文件
text1_line = text1.splitlines()     # 以行进行分割,以便进行对比
text2 = """text2:
This module provides classes and functions for comparing 
includes add string
"""
text2_line = text2.splitlines()
# 创建differ对象
d = difflib.HtmlDiff() #创建Differ对象
# 使用compare方法比较内容
diff = d.make_file(text2_line,text1_line)
# 将输出的对比效果放到一个文件中 --with open 方法
with open('diff.html','w') as f:
    f.write(diff)

在这里插入图片描述

2.1.3 对比nginx 配置文件差异

  1. 准备两个nginx文件
  2. 分别读取两个配置文件
  3. 读取内容
  4. 文件内容的基本判断
  5. 内容的比较
  6. 结果的输出
import difflib
import sys

# 1. 准备文件
# 格式: python pythonauto_30_文件对比-配置实践.py nginx.conf1  nginx.conf2
# 2. 读取文件
# argv -- 命令行;argv[0]脚本名,agrv[1]是第一个参数,依次类推
try:
    textfile1 = sys.argv[1]
    textfile2 = sys.argv[2]
    
# 如果在尝试读取命令行参数时发生了异常(例如,没有提供足够的参数),
# 则会捕获这个异常,并执行except块中的代码。
except Exception as e:
    # str(e)将异常对象e转换为字符串,以便打印。
    print(f"Error: str({e})")
    print("Usage: diff-file.py filename1 filename2")
    sys.exit()
    
# 3.读取内容
def readfile(filename):
    try:
        with open(filename,'r') as f:
            text = f.read().splitlines()	#读取后以行进行分隔
            return text
    except Exception as error:
        print("读取文件错误:{}".format(error))
        sys.exit()

# 4. 文件内容为空的基本判断
if textfile1 == "" or  textfile2 == "":
    print("脚本的参数不允许为空,请检查")
    print(f"Usage: diff-file.py filename1 filename2")
    sys.exit()
# 5. 内容的比较
# 5.1读取文件
text1_line = readfile(textfile1)
text2_line = readfile(textfile2)
# 5.2 创建Htmldiff对象
diff_object = difflib.HtmlDiff()
# 5.3 对文件进行比较
diff_result = diff_object.make_file(text1_line,text2_line)

# 6.输出结果
with open('nginx_diff.html','w') as f:
    f.write(diff_result)

代码封装

定义了一个名为 DiffContent 的类,该类提供了两个主要功能:

  1. 比较两个文件的内容差异,并将差异结果保存为 HTML 文件;
  2. 以及比较两个字符串(文本)的差异,并同样将差异结果保存为 HTML 文件。
import difflib
import os.path
import time
from typing import List

class DiffContent:

    @classmethod
    def _read_file(cls, file_path: str) -> List[str]:
        """
        读取指定路径的文件内容,并将其作为字符串列表返回,每个列表项代表文件的一行
        :param file_path: 文件绝对路径
        :return: 列表,包含文件的所有行
        """
        try:
            with open(file_path, "rb") as f:
                # 二进制方式读取文件内容,并转换为str类型
                lines = f.read().decode('utf-8')
                # 按行进行分割
                text = lines.splitlines()
                return text
        except Exception as e:
            print("ERROR: {}".format(str(e)))
            return []  # 返回空列表以避免后续错误  

    @classmethod
    def compare_diff_by_file(cls, file1: str, file2: str, save_path: str = '') -> None:
        """
        对比文件内容差异,并输出html文件,文件名命名:compare_file1name_file2name.html
        :param file_1:文件1
        :param file_2:文件2
        :param save_path:如果未指定,则在当前目录下保存文件
        :return:
        """
        # 获取文件内容
        file1_content = cls._read_file(file1)
        file2_content = cls._read_file(file2)
        # 创建比较器
        compare = difflib.HtmlDiff()
        res = compare.make_file(file1_content, file2_content)
        # 获取输出html文件的绝对路径
        file1_name = os.path.basename(file_1).split('.')[0]
        file2_name = os.path.basename(file_2).split('.')[0]
        if not file_1_name or not file_2_name:  
            raise ValueError("File names must contain an extension to generate a valid output file name.")  
        if save_path:
            out_file = '{}/compare_{}_{}.html'.format(save_path, file_1_name, file_2_name)
        else:
            out_file = 'compare_{}_{}.html'.format(file_1_name, file_2_name)
        with open(out_file, 'w') as f:
            f.writelines(res)

    @classmethod
    def compare_text(cls, src_text: str, target_text: str, save_path: str = '') -> None:
        """
        比较给定的2个字符串,并输出html文件
        :param src_text:
        :param target_text:
        :param save_path:如果未指定,则在当前目录下保存文件
        :return:
        """
        compare = difflib.HtmlDiff()
        compare_result = compare.make_file(src_text, target_text)
        if save_path:
            out_file = f"{save_path}/compare{int(time.time())}.html"  # 使用整数时间戳避免微秒差异  
        else:
            out_file = 'compare{}.html'.format(str(time.time()).split('.')[0])
        with open(out_file, 'w') as f:
            f.writelines(compare_result)

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部