脚本如何实现文件差异对比功能

wen 实用脚本 1

本文目录导读:

脚本如何实现文件差异对比功能

  1. 核心思想
  2. 方案一:Python 实现(推荐,功能强大)
  3. 方案二:JavaScript 实现(适合 Node.js 或前端)
  4. 方案三:命令行调用(最省事)
  5. 使用建议
  6. 文件差异对比的核心概念解释

实现文件差异对比功能,通常使用逐行比较的算法(类似于 Unix 的 diff 命令),最经典且高效的算法是 最长公共子序列

以下我会用 PythonJavaScript 两种最常用的脚本语言,为你提供完整的实现方案,并包含详细的注释。

核心思想

  1. 读取:将两个文件分别读入内存,按行拆分成列表。
  2. 比对:使用 LCS 或 Myers 差异算法找出两个列表中的相同行和不同行。
  3. 输出:标记出新增、删除、修改的行。

Python 实现(推荐,功能强大)

Python 有非常成熟的内置库 difflib,几乎实现了 diff 命令的全部功能。

简易版:使用 difflib.unified_diff(生成统一格式 diff)

import difflib
import sys
def compare_files_unified(file1_path, file2_path):
    """
    读取两个文件,输出 unified 格式的差异(类似 git diff)
    """
    try:
        with open(file1_path, 'r', encoding='utf-8') as f1, \
             open(file2_path, 'r', encoding='utf-8') as f2:
            lines1 = f1.readlines()
            lines2 = f2.readlines()
            # 生成差异生成器
            diff = difflib.unified_diff(
                lines1, 
                lines2,
                fromfile=file1_path,  # 左侧文件名
                tofile=file2_path,    # 右侧文件名
                lineterm=''           # 避免多余换行
            )
            # 逐行输出结果
            for line in diff:
                print(line)
    except FileNotFoundError as e:
        print(f"文件未找到: {e}", file=sys.stderr)
    except Exception as e:
        print(f"读取文件出错: {e}", file=sys.stderr)
# 示例用法
if __name__ == "__main__":
    # 假设有两个文件 old.txt 和 new.txt
    compare_files_unified('old.txt', 'new.txt')

可视化版:逐行打印带标记的差异(自定义输出格式)

import difflib
def compare_files_detailed(file1_path, file2_path):
    """
    逐行对比并打印带有标记的结果
    + : 新增行 (在 file2 中,不在 file1 中)
    - : 删除行 (在 file1 中,不在 file2 中)
      : 相同行
    ? : 行内差异 (标记有改动的字符)
    """
    with open(file1_path, 'r', encoding='utf-8') as f1, \
         open(file2_path, 'r', encoding='utf-8') as f2:
        lines1 = f1.readlines()
        lines2 = f2.readlines()
    # 使用 Differ 类进行行级对比
    differ = difflib.Differ()
    diff = list(differ.compare(lines1, lines2))
    print(f"对比结果 ({file1_path} vs {file2_path}):")
    print("=" * 60)
    for line in diff:
        if line.startswith('+ '):
            print(f"\033[92m{line}\033[0m", end='')  # 绿色表示新增
        elif line.startswith('- '):
            print(f"\033[91m{line}\033[0m", end='')  # 红色表示删除
        elif line.startswith('? '):
            print(f"\033[93m{line}\033[0m", end='')  # 黄色表示行内改动
        else:
            print(f"  {line}", end='')  # 普通行
# 示例用法
compare_files_detailed('old.txt', 'new.txt')

JavaScript 实现(适合 Node.js 或前端)

如果需要在浏览器或 Node.js 中进行对比,可以使用 diff 这个 npm 包,或者手动实现一个简单的 LCS。

使用 diff 库(推荐,最方便)

首先安装依赖:

npm install diff
// fileDiff.js
const fs = require('fs');
const Diff = require('diff');
function compareFiles(file1Path, file2Path) {
    // 读取文件内容
    const oldContent = fs.readFileSync(file1Path, 'utf8');
    const newContent = fs.readFileSync(file2Path, 'utf8');
    // 执行逐行对比
    const changes = Diff.diffLines(oldContent, newContent);
    // 输出结果
    changes.forEach(part => {
        // value: 行的内容
        // added: 是否是新增
        // removed: 是否是删除
        const prefix = part.added ? '+' : (part.removed ? '-' : ' ');
        // 在控制台用颜色区分
        if (part.added) {
            console.log(`\x1b[32m${prefix} ${part.value}\x1b[0m`); // 绿色
        } else if (part.removed) {
            console.log(`\x1b[31m${prefix} ${part.value}\x1b[0m`); // 红色
        } else {
            console.log(`${prefix} ${part.value}`);
        }
    });
}
// 使用
compareFiles('old.txt', 'new.txt');

前端展示差异(HTML 版本)

// 假设有两个字符串
const oldStr = "第一行\n第二行\n第三行";
const newStr = "第一行\n修改的第二行\n第四行";
// 使用 diff 库 (需要 <script src="diff.js"></script>)
const changes = Diff.diffLines(oldStr, newStr);
// 生成 HTML 用于展示
let displayHtml = '';
changes.forEach(part => {
    const color = part.added ? 'lightgreen' : (part.removed ? 'lightcoral' : 'white');
    // 注意:需要将文本中的 \n 转换为 <br> 才能正常显示换行
    const text = part.value.replace(/\n/g, '<br>');
    displayHtml += `<div style="background-color: ${color}; padding: 2px 5px; margin: 2px 0;">
                        <span style="font-weight: bold; color: ${part.added ? 'green' : (part.removed ? 'red' : 'gray')};">
                            ${part.added ? '+' : (part.removed ? '-' : ' ')}
                        </span>
                        ${text}
                    </div>`;
});
document.getElementById('diffContainer').innerHTML = displayHtml;

命令行调用(最省事)

如果你的脚本只是需要简单的执行 diff 命令并获取结果,可以直接使用子进程调用系统命令。

Python 调用系统 diff

import subprocess
import sys
def diff_system(file1, file2):
    try:
        # 调用系统 diff 命令,-u 表示 unified 格式,-w 忽略空白
        result = subprocess.run(
            ['diff', '-u', file1, file2], 
            capture_output=True, 
            text=True,
            check=False  # 有差异时不抛出异常
        )
        if result.returncode == 0:
            print("两个文件完全相同")
        else:
            print(result.stdout)
    except FileNotFoundError:
        print("系统中未找到 diff 命令 (Linux/Mac 默认有,Windows 需要 Git Bash 等)", file=sys.stderr)
# 使用
diff_system('old.txt', 'new.txt')

使用建议

场景 推荐方案
Python 脚本 difflib (内置库,无依赖)
Node.js 项目 diff npm 包 (功能全面)
前端可视化 diff 库 + 自定义 CSS
快速验证 / 终端工具 调用系统 diff 命令
大文件(百 MB 以上) 使用 git diff --no-index 或分块读取

文件差异对比的核心概念解释

  • 逐行对比:将文件视为行的数组。
  • 上下文unified diff 在差异前后显示几行未修改的行,便于理解上下文。
  • 最长公共子序列:算法的基础,找出两个序列中相同的部分,剩下的就是差异。
  • Myers 算法git 使用的算法,通常比基础的 LCS 更快,输出更紧凑。

希望这些代码能直接帮到你!根据你的实际需求(终端输出、前端展示、还是云端处理),选择最合适的一种即可。

抱歉,评论功能暂时关闭!