winmerge对比excel,word文件

本文介绍如何通过WinMerge及其插件xdocdiffPlugin实现不同文档之间的对比。首先需要安装WinMerge,接着按照步骤配置插件文件,即可进行文档对比。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

winmerge里面有一个插件xdocdiffPlugin_1_0_6d.zip可以对比各种文档。

1.先安装winmerge

然后选择菜单的插件里面的自动展开

2。xdocdiffPlugin_1_0_6d.zip解压,把xdoc2txt.exe、zlib.dll拷WinMerge.exe平级的文件夹下

3。把amb_xdocdiffPlugin.dll拷MergePlugins文件夹下

 

import os import subprocess import shutil import time import tkinter as tk from tkinter import filedialog, ttk, scrolledtext, messagebox, PhotoImage import win32com.client as win32 import threading import tempfile import queue import traceback import webbrowser class DiffProcessorApp: def __init__(self, root): self.root = root root.title("高级文件比较工具") root.geometry("1000x700") root.configure(bg="#f5f5f5") # 创建现代风格主题 self.style = ttk.Style() self.style.theme_use('clam') # 自定义主题颜色 self.style.configure('TButton', font=('Segoe UI', 10, 'bold'), borderwidth=1, foreground="#333", background="#4CAF50", bordercolor="#388E3C", relief="flat", padding=8, anchor="center") self.style.map('TButton', background=[('active', '#388E3C'), ('disabled', '#BDBDBD')], foreground=[('disabled', '#9E9E9E')]) self.style.configure('TLabel', font=('Segoe UI', 9), background="#f5f5f5") self.style.configure('TLabelframe', font=('Segoe UI', 10, 'bold'), background="#f5f5f5", relief="flat", borderwidth=2) self.style.configure('TLabelframe.Label', font=('Segoe UI', 10, 'bold'), background="#f5f5f5", foreground="#2E7D32") self.style.configure('Treeview', font=('Segoe UI', 9), rowheight=25) self.style.configure('Treeview.Heading', font=('Segoe UI', 9, 'bold')) # 创建主框架 main_frame = ttk.Frame(root, padding="15") main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 标题区域 header_frame = ttk.Frame(main_frame) header_frame.pack(fill=tk.X, pady=(0, 15)) # 添加标题图标 try: icon = PhotoImage(file="folder_icon.png") self.icon_label = ttk.Label(header_frame, image=icon) self.icon_label.image = icon self.icon_label.pack(side=tk.LEFT, padx=(0, 10)) except: self.icon_label = ttk.Label(header_frame, text="📁", font=("Arial", 24)) self.icon_label.pack(side=tk.LEFT, padx=(0, 10)) title_label = ttk.Label(header_frame, text="高级文件比较工具", font=("Segoe UI", 18, "bold"), foreground="#2E7D32") title_label.pack(side=tk.LEFT) # 文件选择区域 file_frame = ttk.LabelFrame(main_frame, text="文件夹选择", padding="12") file_frame.pack(fill=tk.X, pady=5) # 文件夹选择 self.old_folder_entry, _ = self.create_folder_selector(file_frame, "原始文件夹:") self.new_folder_entry, _ = self.create_folder_selector(file_frame, "修改后文件夹:") # 比较选项区域 options_frame = ttk.LabelFrame(main_frame, text="比较选项", padding="12") options_frame.pack(fill=tk.X, pady=5) # 递归比较选项 self.recursive_var = tk.BooleanVar(value=True) recursive_check = ttk.Checkbutton(options_frame, text="递归比较文件夹", variable=self.recursive_var) recursive_check.grid(row=0, column=0, padx=10, pady=5, sticky=tk.W) # 文件过滤 filter_frame = ttk.Frame(options_frame) filter_frame.grid(row=0, column=1, padx=10, pady=5, sticky=tk.W) ttk.Label(filter_frame, text="文件过滤:").pack(side=tk.LEFT, padx=(0, 5)) self.filter_var = tk.StringVar(value="*.*") filter_entry = ttk.Entry(filter_frame, textvariable=self.filter_var, width=15) filter_entry.pack(side=tk.LEFT) # 文件报告选项 self.file_report_var = tk.BooleanVar(value=True) file_report_check = ttk.Checkbutton(options_frame, text="生成文件比较报告", variable=self.file_report_var) file_report_check.grid(row=0, column=2, padx=10, pady=5, sticky=tk.W) # 添加报告格式选择 report_frame = ttk.Frame(options_frame) report_frame.grid(row=1, column=0, columnspan=3, padx=10, pady=5, sticky=tk.W) ttk.Label(report_frame, text="报告格式:").pack(side=tk.LEFT, padx=(0, 5)) self.report_format_var = tk.StringVar(value="html") ttk.Radiobutton(report_frame, text="HTML", variable=self.report_format_var, value="html").pack(side=tk.LEFT, padx=5) ttk.Radiobutton(report_frame, text="XML", variable=self.report_format_var, value="xml").pack(side=tk.LEFT, padx=5) # 输出设置区域 self.excel_frame = ttk.LabelFrame(main_frame, text="输出设置", padding="12") self.excel_frame.pack(fill=tk.X, pady=5) # 目标Excel选择 ttk.Label(self.excel_frame, text="目标Excel文件:").grid(row=0, column=0, sticky=tk.W, padx=5, pady=5) self.excel_file_entry = ttk.Entry(self.excel_frame, width=60) self.excel_file_entry.grid(row=0, column=1, padx=5, pady=5) ttk.Button(self.excel_frame, text="浏览...", command=lambda: self.select_file(self.excel_file_entry, [("Excel文件", "*.xlsx *.xlsm")])).grid(row=0, column=2, padx=5, pady=5) # WinMerge路径设置 winmerge_frame = ttk.Frame(self.excel_frame) winmerge_frame.grid(row=1, column=0, columnspan=3, sticky=tk.W, padx=5, pady=5) ttk.Label(winmerge_frame, text="WinMerge路径:").grid(row=0, column=0, sticky=tk.W) self.winmerge_entry = ttk.Entry(winmerge_frame, width=60) self.winmerge_entry.grid(row=0, column=1, padx=5) self.winmerge_entry.insert(0, r"E:\App\WinMerge\WinMerge2.16.12.0\WinMergeU.exe") # 默认路径 ttk.Button(winmerge_frame, text="浏览...", command=lambda: self.select_file(self.winmerge_entry, [("WinMerge 可执行文件", "*.exe")])).grid(row=0, column=2) # 执行按钮区域 button_frame = ttk.Frame(main_frame) button_frame.pack(fill=tk.X, pady=10) self.run_button = ttk.Button(button_frame, text="执行比较", command=self.start_processing, width=20, style='TButton') self.run_button.pack(side=tk.LEFT) # 停止按钮 self.stop_button = ttk.Button(button_frame, text="停止", command=self.stop_processing, width=10, state=tk.DISABLED) self.stop_button.pack(side=tk.LEFT, padx=10) # 查看报告按钮 self.view_report_button = ttk.Button(button_frame, text="查看报告", command=self.view_report, width=10, state=tk.DISABLED) self.view_report_button.pack(side=tk.LEFT, padx=10) # 进度条 self.progress = ttk.Progressbar(main_frame, orient=tk.HORIZONTAL, length=700, mode='determinate') self.progress.pack(fill=tk.X, pady=5) # 状态信息 status_frame = ttk.Frame(main_frame) status_frame.pack(fill=tk.X, pady=5) self.status_var = tk.StringVar(value="准备就绪") status_label = ttk.Label(status_frame, textvariable=self.status_var, font=("Segoe UI", 9), foreground="#2E7D32") status_label.pack(side=tk.LEFT) # 日志和预览区域 notebook = ttk.Notebook(main_frame) notebook.pack(fill=tk.BOTH, expand=True, pady=5) # 文件夹结构标签 tree_frame = ttk.Frame(notebook, padding="5") notebook.add(tree_frame, text="文件夹结构") # 创建树形视图 self.tree = ttk.Treeview(tree_frame, columns=("Status"), show="tree") self.tree.heading("#0", text="文件夹结构", anchor=tk.W) self.tree.heading("Status", text="状态", anchor=tk.W) self.tree.column("#0", width=400) self.tree.column("Status", width=100) vsb = ttk.Scrollbar(tree_frame, orient="vertical", command=self.tree.yview) hsb = ttk.Scrollbar(tree_frame, orient="horizontal", command=self.tree.xview) self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) self.tree.grid(row=0, column=0, sticky="nsew") vsb.grid(row=0, column=1, sticky="ns") hsb.grid(row=1, column=0, sticky="ew") # 日志标签 log_frame = ttk.Frame(notebook, padding="5") notebook.add(log_frame, text="执行日志") self.log_text = scrolledtext.ScrolledText(log_frame, height=10, wrap=tk.WORD, font=("Consolas", 9)) self.log_text.pack(fill=tk.BOTH, expand=True) self.log_text.config(state=tk.DISABLED) # 设置网格权重 tree_frame.grid_rowconfigure(0, weight=1) tree_frame.grid_columnconfigure(0, weight=1) # 线程控制 self.processing = False self.queue = queue.Queue() self.last_report_path = None # 启动队列处理 self.root.after(100, self.process_queue) def create_folder_selector(self, parent, label_text): """创建文件夹选择器组件""" frame = ttk.Frame(parent) frame.pack(fill=tk.X, pady=5) ttk.Label(frame, text=label_text).grid(row=0, column=0, sticky=tk.W, padx=5, pady=5) entry = ttk.Entry(frame, width=70) entry.grid(row=0, column=1, padx=5, pady=5) button = ttk.Button(frame, text="浏览文件夹...", command=lambda: self.select_folder(entry)) button.grid(row=0, column=2, padx=5, pady=5) return entry, button def select_folder(self, entry): """选择文件夹""" foldername = filedialog.askdirectory() if foldername: entry.delete(0, tk.END) entry.insert(0, foldername) # 自动填充文件夹结构 self.populate_folder_tree(foldername) def select_file(self, entry, filetypes=None): """选择文件""" if filetypes is None: filetypes = [("所有文件", "*.*")] filename = filedialog.askopenfilename(filetypes=filetypes) if filename: entry.delete(0, tk.END) entry.insert(0, filename) def populate_folder_tree(self, path): """填充文件夹结构树""" self.tree.delete(*self.tree.get_children()) if not os.path.isdir(path): return # 添加根节点 root_node = self.tree.insert("", "end", text=os.path.basename(path), values=("文件夹",), open=True) self.add_tree_nodes(root_node, path) def add_tree_nodes(self, parent, path): """递归添加树节点""" try: for item in os.listdir(path): item_path = os.path.join(path, item) if os.path.isdir(item_path): node = self.tree.insert(parent, "end", text=item, values=("文件夹",)) self.add_tree_nodes(node, item_path) else: self.tree.insert(parent, "end", text=item, values=("文件",)) except PermissionError: self.log_message(f"权限错误: 无法访问 {path}") def log_message(self, message): """记录日志消息""" self.queue.put(("log", message)) def update_progress(self, value): """更新进度条""" self.queue.put(("progress", value)) def update_status(self, message): """更新状态信息""" self.queue.put(("status", message)) def process_queue(self): """处理线程队列中的消息""" try: while not self.queue.empty(): msg_type, data = self.queue.get_nowait() if msg_type == "log": self.log_text.config(state=tk.NORMAL) self.log_text.insert(tk.END, data + "\n") self.log_text.see(tk.END) self.log_text.config(state=tk.DISABLED) elif msg_type == "progress": self.progress['value'] = data elif msg_type == "status": self.status_var.set(data) except queue.Empty: pass self.root.after(100, self.process_queue) def view_report(self): """查看生成的报告""" if self.last_report_path and os.path.exists(self.last_report_path): try: webbrowser.open(self.last_report_path) except Exception as e: messagebox.showerror("错误", f"无法打开报告: {str(e)}") else: messagebox.showwarning("警告", "没有可用的报告文件") def process_folders(self, old_path, new_path, excel_file): """处理文件比较的线程函数""" output_html = None try: # 设置报告目录为Excel文件所在目录 report_dir = os.path.dirname(excel_file) os.makedirs(report_dir, exist_ok=True) # 步骤1: 生成HTML差异文件 self.update_status("生成HTML差异文件...") self.update_progress(30) # 使用临时文件存储HTML报告 with tempfile.NamedTemporaryFile(suffix=".html", delete=False) as temp_file: output_html = temp_file.name winmerge_path = self.winmerge_entry.get() if not self.run_winmerge(winmerge_path, old_path, new_path, output_html, report_dir): self.update_status("WinMerge执行失败") return # 步骤2: 将HTML文件复制到Excel目录 self.update_status("复制HTML报告到目标目录...") self.update_progress(60) if report_dir: target_html = os.path.join(report_dir, "diff_report.html") try: shutil.copy(output_html, target_html) self.log_message(f"已将HTML文件复制到: {target_html}") self.last_report_path = target_html self.view_report_button.config(state=tk.NORMAL) except Exception as e: self.log_message(f"文件复制失败: {str(e)}") self.last_report_path = output_html # 步骤3: 打开Excel并等待用户操作 self.update_status("打开Excel文件...") self.update_progress(80) if not self.open_excel_file(excel_file): self.update_status("打开Excel失败") return # 完成 self.update_progress(100) self.update_status("处理完成!") self.log_message("文件比较流程执行完毕") messagebox.showinfo("完成", "已生成HTML报告并打开Excel文件") except Exception as e: error_msg = f"执行过程中发生错误: {str(e)}\n{traceback.format_exc()}" self.log_message(error_msg) self.update_status("执行失败") messagebox.showerror("错误", f"处理失败: {str(e)}") finally: # 重新启用执行按钮 if self.processing: self.stop_processing() # 清理临时文件 if output_html and os.path.exists(output_html): try: os.remove(output_html) except: pass def start_processing(self): """启动处理线程""" if self.processing: self.log_message("警告: 处理正在进行中") return # 获取路径 old_path = self.old_folder_entry.get() new_path = self.new_folder_entry.get() excel_file = self.excel_file_entry.get() # 详细路径验证 validation_errors = [] if not old_path: validation_errors.append("原始文件夹路径为空") elif not os.path.isdir(old_path): validation_errors.append(f"原始文件夹路径无效: {old_path}") if not new_path: validation_errors.append("新文件夹路径为空") elif not os.path.isdir(new_path): validation_errors.append(f"新文件夹路径无效: {new_path}") if not excel_file: validation_errors.append("Excel文件路径为空") elif not excel_file.lower().endswith(('.xlsx', '.xlsm')): validation_errors.append("Excel文件必须是.xlsx或.xlsm格式") winmerge_path = self.winmerge_entry.get() if not winmerge_path or not os.path.exists(winmerge_path): validation_errors.append("WinMerge路径无效或未设置") if validation_errors: self.log_message("错误: " + "; ".join(validation_errors)) messagebox.showerror("输入错误", "\n".join(validation_errors)) return # 禁用执行按钮,启用停止按钮 self.run_button.config(state=tk.DISABLED) self.stop_button.config(state=tk.NORMAL) self.view_report_button.config(state=tk.DISABLED) self.processing = True # 启动处理线程 thread = threading.Thread(target=self.process_folders, args=(old_path, new_path, excel_file)) thread.daemon = True thread.start() self.log_message("处理线程已启动") def run_winmerge(self, winmerge_path, path1, path2, output_html, report_dir): """调用WinMerge生成HTML差异文件 - 修复路径和卡顿问题""" # 验证WinMerge可执行文件 if not os.path.exists(winmerge_path): self.log_message(f"错误: WinMerge路径不存在 {winmerge_path}") return False # 确保报告目录存在 os.makedirs(report_dir, exist_ok=True) # 构建WinMerge命令 - 移除第三组路径参数 winmerge_cmd = [ winmerge_path, '/u', '/nosplash', # 不显示启动画面 '/dl', 'Base', '/dr', 'Modified', '/or', output_html, # 文件夹报告输出文件 path1, path2 # 只传递两个文件夹路径 ] # 添加递归选项 if self.recursive_var.get(): winmerge_cmd.insert(1, '/r') # 添加文件报告参数 - 可选 if self.file_report_var.get(): winmerge_cmd.extend([ '/reporttype', self.report_format_var.get(), '/reportoutput', report_dir # 文件报告输出目录 ]) # 添加文件过滤 file_filter = self.filter_var.get() if file_filter and file_filter != "*.*": winmerge_cmd.extend(['-f', file_filter]) # 添加非交互模式参数,防止卡在界面 winmerge_cmd.extend(['/noninteractive']) self.log_message(f"执行WinMerge命令: {' '.join(winmerge_cmd)}") try: # 使用Popen而不是run,避免阻塞 process = subprocess.Popen( winmerge_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, creationflags=subprocess.CREATE_NO_WINDOW ) # 等待进程完成,设置超时 try: stdout, stderr = process.communicate(timeout=300) # 5分钟超时 except subprocess.TimeoutExpired: process.kill() stdout, stderr = process.communicate() self.log_message("WinMerge执行超时(300秒),已终止进程") return False if process.returncode == 0: self.log_message(f"HTML差异报告生成完成: {output_html}") # 检查文件夹报告文件是否存在 if os.path.exists(output_html) and os.path.getsize(output_html) > 0: self.log_message("文件夹报告生成成功") else: self.log_message("警告: 文件夹报告文件为空或不存在") # 检查文件报告 if self.file_report_var.get(): report_files = [f for f in os.listdir(report_dir) if f.endswith(('.html', '.xml'))] if report_files: self.log_message(f"文件报告生成成功 ({len(report_files)}个文件)") else: self.log_message("警告: 没有生成文件报告") return True else: error_msg = f"WinMerge执行失败(退出码{process.returncode}): {stderr}" self.log_message(error_msg) return False except Exception as e: self.log_message(f"WinMerge执行错误: {str(e)}") return False def open_excel_file(self, excel_path): """打开Excel文件并等待用户操作""" self.log_message("正在打开Excel文件...") try: # 验证Excel文件存在 if not os.path.exists(excel_path): self.log_message(f"错误: Excel文件不存在 {excel_path}") return False # 使用系统默认程序打开Excel文件 os.startfile(excel_path) self.log_message(f"Excel文件已打开: {excel_path}") # 提示用户手动操作 self.log_message("Excel已打开,请手动执行操作") messagebox.showinfo("Excel已打开", "Excel文件已打开,请手动执行所需操作") return True except Exception as e: self.log_message(f"打开Excel文件失败: {str(e)}\n{traceback.format_exc()}") return False def stop_processing(self): """停止处理""" self.processing = False self.stop_button.config(state=tk.DISABLED) self.run_button.config(state=tk.NORMAL) self.view_report_button.config(state=tk.NORMAL) self.update_status("操作已停止") if __name__ == "__main__": root = tk.Tk() app = DiffProcessorApp(root) root.mainloop() 我想做一个控制面板,实现的自动化功能包括以下几个点: 1、界面要美观,简约实用。 2、首先能够调用winmerge去实现新旧两个文件夹的的对比,生成文件比较报告与文件比较报告。 3、将文件比较报告与文件比较报告放到与我的一个excel文件所在的位置。 4、打开excel文档,并提示我手动点击sheet一览中I1的名称为作成按钮。 5、等待执行结束。 6、要求有执行日志与进度条显示 举个例子,原来的逻辑中我需要手动去调用winmerge生成文件比较报告与文件比较报告,然后将这两个报告与我需要作成的的excel文件放在一起,然后我再打开我的excel文件,点击excel文件里面的作成按钮。现在我想要作成的是点击比较,自动生成文件比较报告与文件比较报告html格式,然后自动打开我的execl文件,我再点击作成 但是现在我的代码出现了问题,在生成报告的时候,会出现一个弹窗然后立马被关闭。应该是没有正确生成报告,因为点击生成的报告diff_report.html,里面是空白的。请基于我的代码帮助我解决
最新发布
07-12
我们经常会遇到这样的问题: 1、 撰写工作报告、演讲文稿或相关方案,经常是改了再写,写了再改,有时候甚至需要预备多个版本。通常的做法是将每个版本的文档单独保存为一个文件,相似的文件多了,不仅占用了磁盘空间,而且管理起来也不方便。 2、 “客户昨天把合同发给小张,说合同中做了些调整,让小张看看后如果没有什么疑问就可以签字了”,合同中的一字之差、一个标点都有可能使问题性质大变,而这些细微差别很难人工识别。 3、 “小王,昨天领导看了你写的财务方案,做了一些修改,你最后再完善一下。”今天一上班,主任就给小王安排了任务。老总究竟修改了哪些地方?怎么样才能快速精确地比较出两份文件的异同呢?难道去问老总?用眼睛直接观察?小王犯愁了。 相信类似的问题,大家在日常工作中也会经常遇到,面对电脑以及公司网络上各种版本的文件,还有一些修改过多少次的文档,如何知道这些相似文档的差别在哪些地方、都进行过哪些改动,有一些只有极为细小的区别,如果仅仅凭借手工来逐个查找文档的不同之处,会浪费不少时间和精力。 有没有什么好办法可以解决这个问题呢?当然有! 现在有很多种文件比较工具可以用来查找两个文本文件是否相同,而且往往比使用Word更加直观,例如“叮当文档比较器(DD-Compare)”就是一个很有特色的文件直观比较工具,她可以比较两个文件的不同处,提供在同一窗口内开左右两个窗格显示两个文件的内容,你可用鼠标或键盘操作进行对照。 下面简单介绍一下叮当文档比较器如何帮助你一目了然识别两个文档之间的差异:FileCompare 第一步、下载(下载地址:http://www.ddpace.com)叮当文档比较器(DD-Compare),并完成安装,安装过程比较简单,这里不做具体介绍; 第二步、到叮当文档比较器软件的官方网站注册一下用户,只需要姓名和电子邮件就可以了; 第三步、选择要比较文件文件格式支持doc、docx、xls、xlsx、ppt、pptx、txt、htm、html等9种格式。 第四步、点击“比较上述两个文件”,显示出两个文件的差异所在,如下图所示。 利用叮当文档比较器(DD-Compare)的比较文档功能,可以大大减轻你的工作量,提高准确性和工作效率。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值