本文目录导读:

实现文件差异对比功能,通常使用逐行比较的算法(类似于 Unix 的 diff 命令),最经典且高效的算法是 最长公共子序列。
以下我会用 Python 和 JavaScript 两种最常用的脚本语言,为你提供完整的实现方案,并包含详细的注释。
核心思想
- 读取:将两个文件分别读入内存,按行拆分成列表。
- 比对:使用 LCS 或 Myers 差异算法找出两个列表中的相同行和不同行。
- 输出:标记出新增、删除、修改的行。
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 更快,输出更紧凑。
希望这些代码能直接帮到你!根据你的实际需求(终端输出、前端展示、还是云端处理),选择最合适的一种即可。