本文目录导读:

我来介绍几种编写文件差异对比脚本的方法,涵盖不同场景和复杂度。
简易版本(使用系统命令)
Linux/Unix 系统
#!/bin/bash
# diff_files.sh
if [ $# -ne 2 ]; then
echo "用法: $0 <文件1> <文件2>"
exit 1
fi
if [ ! -f "$1" ] || [ ! -f "$2" ]; then
echo "错误: 文件不存在"
exit 1
fi
echo "=== 差异对比结果 ==="
diff "$1" "$2"
Python 实现(功能增强版)
基础版本
#!/usr/bin/env python3
# file_diff.py
import difflib
import sys
def compare_files(file1, file2):
"""对比两个文件并输出差异"""
try:
with open(file1, 'r', encoding='utf-8') as f1:
lines1 = f1.readlines()
with open(file2, 'r', encoding='utf-8') as f2:
lines2 = f2.readlines()
# 创建差异比较器
differ = difflib.HtmlDiff()
# 生成HTML格式的差异报告
html_diff = differ.make_file(
lines1, lines2,
fromdesc=file1,
todesc=file2
)
# 生成文本格式的差异
text_diff = difflib.unified_diff(
lines1, lines2,
fromfile=file1,
tofile=file2,
lineterm='\n'
)
return list(text_diff), html_diff
except FileNotFoundError as e:
return None, str(e)
def print_text_diff(diff_lines):
"""打印文本差异"""
for line in diff_lines:
if line.startswith('+'):
print(f" \033[32m{line}\033[0m") # 绿色(新增)
elif line.startswith('-'):
print(f" \033[31m{line}\033[0m") # 红色(删除)
elif line.startswith('@@'):
print(f" \033[33m{line}\033[0m") # 黄色(位置)
else:
print(f" {line}")
def main():
if len(sys.argv) != 3:
print("用法: python file_diff.py <文件1> <文件2>")
sys.exit(1)
file1 = sys.argv[1]
file2 = sys.argv[2]
text_diff, html_diff = compare_files(file1, file2)
if text_diff:
print(f"差异对比结果 ({file1} vs {file2}):")
print("=" * 50)
# 生成HTML报告
with open('diff_report.html', 'w', encoding='utf-8') as f:
f.write(html_diff)
print_text_diff(text_diff)
print(f"\nHTML报告已保存到: diff_report.html")
else:
print(f"文件完全相同 或 错误: {html_diff}")
if __name__ == "__main__":
main()
增强版本(支持更多功能)
#!/usr/bin/env python3
# advanced_file_diff.py
import hashlib
import difflib
import os
import sys
from collections import Counter
class FileComparer:
def __init__(self, file1, file2, encoding='utf-8'):
self.file1 = file1
self.file2 = file2
self.encoding = encoding
def read_files(self):
"""读取文件内容"""
try:
with open(self.file1, 'r', encoding=self.encoding) as f:
content1 = f.read()
with open(self.file2, 'r', encoding=self.encoding) as f:
content2 = f.read()
return content1, content2
except Exception as e:
print(f"读取文件失败: {e}")
return None, None
def file_hash(self, filename):
"""计算文件哈希值"""
with open(filename, 'rb') as f:
return hashlib.md5(f.read()).hexdigest()
def quick_check(self):
"""快速检查是否相同"""
return self.file_hash(self.file1) == self.file_hash(self.file2)
def get_missing_lines(self):
"""找出每个文件独有的行"""
content1, content2 = self.read_files()
if content1 is None or content2 is None:
return {}, {}
lines1 = content1.splitlines()
lines2 = content2.splitlines()
# 使用Counter统计每行的出现次数
counter1 = Counter(lines1)
counter2 = Counter(lines2)
# 找出独有的行
missing_in_file2 = counter1 - counter2
missing_in_file1 = counter2 - counter1
return dict(missing_in_file2), dict(missing_in_file1)
def generate_side_by_side_diff(self):
"""生成并排对比"""
content1, content2 = self.read_files()
if content1 is None or content2 is None:
return None
lines1 = content1.splitlines()
lines2 = content2.splitlines()
# 使用SequenceMatcher进行智能对比
matcher = difflib.SequenceMatcher(None, lines1, lines2)
side_by_side = []
for tag, i1, i2, j1, j2 in matcher.get_opcodes():
if tag == 'equal':
for k in range(i1, i2):
side_by_side.append(f" | {lines1[k]} | {lines2[j1 + (k - i1)]} |")
elif tag == 'delete':
for k in range(i1, i2):
side_by_side.append(f"- | {lines1[k]} | {'':<20} |")
elif tag == 'insert':
for k in range(j1, j2):
side_by_side.append(f"+ | {'':<20} | {lines2[k]} |")
elif tag == 'replace':
for k in range(max(i2 - i1, j2 - j1)):
ln1 = lines1[i1 + k] if i1 + k < i2 else ""
ln2 = lines2[j1 + k] if j1 + k < j2 else ""
side_by_side.append(f"* | {ln1} | {ln2} |")
return side_by_side
def generate_statistics(self):
"""生成统计信息"""
content1, content2 = self.read_files()
if content1 is None or content2 is None:
return {}
lines1 = content1.splitlines()
lines2 = content2.splitlines()
stats = {
"文件1行数": len(lines1),
"文件2行数": len(lines2),
"总字符数(文件1)": len(content1),
"总字符数(文件2)": len(content2)
}
# 计算差异行数
matcher = difflib.SequenceMatcher(None, lines1, lines2)
diffs = 0
for tag, i1, i2, j1, j2 in matcher.get_opcodes():
if tag != 'equal':
diffs += max(i2 - i1, j2 - j1)
stats["差异行数"] = diffs
stats["相似度百分比"] = round(100 * (1 - diffs/max(len(lines1), len(lines2), 1)), 2)
return stats
def main():
if len(sys.argv) != 3:
print("用法: python advanced_file_diff.py <文件1> <文件2>")
sys.exit(1)
file1, file2 = sys.argv[1], sys.argv[2]
if not os.path.exists(file1) or not os.path.exists(file2):
print("错误: 文件不存在")
sys.exit(1)
comparer = FileComparer(file1, file2)
print(f"对比文件: {file1} vs {file2}")
print("=" * 60)
# 快速检查
if comparer.quick_check():
print("✅ 文件完全相同")
else:
print("⚠️ 文件存在差异")
# 显示统计信息
stats = comparer.generate_statistics()
print("\n📊 统计信息:")
for key, value in stats.items():
print(f" {key}: {value}")
# 显示详细差异
print("\n📝 详细对比:")
side_by_side = comparer.generate_side_by_side_diff()
if side_by_side:
for line in side_by_side:
print(line)
# 显示独有的行
missing1, missing2 = comparer.get_missing_lines()
if missing1:
print(f"\n🔍 仅在 {file1} 中存在的行:")
for line, count in missing1.items():
print(f" × {line} (出现{count}次)")
if missing2:
print(f"\n🔍 仅在 {file2} 中存在的行:")
for line, count in missing2.items():
print(f" × {line} (出现{count}次)")
if __name__ == "__main__":
main()
使用第三方库(更强大的功能)
安装依赖
pip install filecmp2
使用 filecmp2
#!/usr/bin/env python3
# filecmp_diff.py
import filecmp
import sys
def compare_simple(file1, file2):
"""简单文件对比"""
comparison = filecmp.cmp(file1, file2, shallow=False)
if comparison:
print("✅ 文件完全相同")
else:
print("❌ 文件不同")
# 获取具体差异
result = filecmp.cmpfiles(
'.', '.', [file1, file2],
shallow=False
)
print(f"相同文件: {result[0]}")
print(f"不同文件: {result[1]}")
print(f"错误文件: {result[2]}")
if __name__ == "__main__":
if len(sys.argv) != 3:
print("用法: python filecmp_diff.py <文件1> <文件2>")
sys.exit(1)
compare_simple(sys.argv[1], sys.argv[2])
带GUI的可视化工具
#!/usr/bin/env python3
# gui_file_diff.py
import tkinter as tk
from tkinter import filedialog, ttk
import difflib
class FileDiffGUI:
def __init__(self, root):
self.root = root
self.root.title("文件差异对比工具")
self.root.geometry("800x600")
self.setup_ui()
def setup_ui(self):
"""设置界面"""
# 文件选择区域
file_frame = ttk.Frame(self.root, padding="10")
file_frame.grid(row=0, column=0, sticky=(tk.W, tk.E))
ttk.Button(file_frame, text="选择文件1",
command=self.select_file1).grid(row=0, column=0, padx=5)
self.file1_label = ttk.Label(file_frame, text="未选择")
self.file1_label.grid(row=0, column=1, padx=5)
ttk.Button(file_frame, text="选择文件2",
command=self.select_file2).grid(row=1, column=0, padx=5)
self.file2_label = ttk.Label(file_frame, text="未选择")
self.file2_label.grid(row=1, column=1, padx=5)
ttk.Button(file_frame, text="开始对比",
command=self.compare_files).grid(row=2, column=0, pady=10)
# 对比结果区域
self.result_text = tk.Text(self.root, wrap=tk.NONE, height=20)
self.result_text.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# 滚动条
scrollbar = ttk.Scrollbar(self.root, orient="vertical",
command=self.result_text.yview)
scrollbar.grid(row=1, column=1, sticky=(tk.N, tk.S))
self.result_text.configure(yscrollcommand=scrollbar.set)
# 配置Grid权重
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(1, weight=1)
def select_file1(self):
filename = filedialog.askopenfilename()
if filename:
self.file1_label.config(text=filename)
self.file1 = filename
def select_file2(self):
filename = filedialog.askopenfilename()
if filename:
self.file2_label.config(text=filename)
self.file2 = filename
def compare_files(self):
"""执行文件对比"""
if not hasattr(self, 'file1') or not hasattr(self, 'file2'):
self.result_text.insert(tk.END, "请先选择两个文件!")
return
self.result_text.delete(1.0, tk.END)
try:
with open(self.file1, 'r', encoding='utf-8') as f1:
lines1 = f1.readlines()
with open(self.file2, 'r', encoding='utf-8') as f2:
lines2 = f2.readlines()
differ = difflib.unified_diff(lines1, lines2, fromfile='文件1', tofile='文件2')
for line in differ:
self.result_text.insert(tk.END, line)
except Exception as e:
self.result_text.insert(tk.END, f"错误: {e}")
if __name__ == "__main__":
root = tk.Tk()
app = FileDiffGUI(root)
root.mainloop()
使用 Bash 脚本(支持中文内容)
#!/bin/bash
# smart_diff.sh
compare_with_color() {
local file1="$1"
local file2="$2"
echo "文件: $file1 vs $file2"
echo "================================"
# 检查文件是否相同
if cmp -s "$file1" "$file2"; then
echo -e "\033[32m✅ 文件内容完全相同\033[0m"
return 0
fi
# 显示行数差异
local lines1=$(wc -l < "$file1")
local lines2=$(wc -l < "$file2")
echo "行数: 文件1=$lines1, 文件2=$lines2"
# 显示具体差异(带行号对比)
diff --side-by-side --suppress-common-lines "$file1" "$file2" | \
while IFS= read -r line; do
if [[ "$line" == *"|"* ]]; then
echo -e "\033[33m$line\033[0m" # 黄色表示修改
elif [[ "$line" == *"<"* ]]; then
echo -e "\033[31m$line\033[0m" # 红色表示删除
elif [[ "$line" == *">"* ]]; then
echo -e "\033[32m$line\033[0m" # 绿色表示新增
else
echo "$line"
fi
done
echo -e "\n差异统计:"
diff_lines=$(diff "$file1" "$file2" | grep -c '^[<>]')
echo -e "\033[31m删除: $(diff "$file1" "$file2" | grep -c '^<') 行\033[0m"
echo -e "\033[32m新增: $(diff "$file1" "$file2" | grep -c '^>') 行\033[0m"
echo "总差异: $diff_lines 行"
}
# 主程序
if [ "$#" -ne 2 ]; then
echo "用法: $0 <文件1> <文件2>"
exit 1
fi
compare_with_color "$1" "$2"
使用方法
-
保存脚本:将上述任一脚本保存为
.py或.sh文件 -
添加执行权限(如果使用脚本):
chmod +x script_name -
运行:
# Python版本 python3 file_diff.py file1.txt file2.txt # Bash版本 ./smart_diff.sh file1.txt file2.txt # GUI版本 python3 gui_file_diff.py
功能特点
- ✅ 支持彩色输出,便于区分新增/删除/修改
- ✅ 可生成统计信息(行数、相似度等)
- ✅ 支持并排对比模式
- ✅ 可生成HTML格式报告
- ✅ 支持大文件处理
- ✅ 可选择图形界面版本
根据你的具体需求选择合适的版本即可,如果只需要简单的比较,使用系统命令 diff 就足够了;如果需要更详细的分析和可视化,建议使用Python版本。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播