详情

首页手游攻略 大模型手搓文件对比工具(6):差异不用再手选

大模型手搓文件对比工具(6):差异不用再手选

佚名 2026-08-03 10:26:12

上一期,我没有继续加功能,而是先给这个文件对比工具补了一份开发计划。

计划里的 P0 只有一件事:改掉内容对比编辑器里最难用的操作。

旧版虽然能标出左右文件的不同内容,也能向左、向右复制,但每次都要先手动选中文字。选少了,内容不完整;选多了,又可能把相邻代码一起覆盖。文件里只有一两处差异时还能忍,差异多了以后,操作比直接打开两个编辑器修改还麻烦。

所以第 6 期正式开始做 P0:让程序识别每一处连续差异,并在旁边直接放 ,点击一次只处理当前这一块。

旧版的问题不在按钮,而在差异判断

旧版编辑器中间有固定的左右复制按钮。它做的事情很简单:读取当前选中的文字,再替换另一侧光标位置的内容。

这种实现写起来不难,但把最麻烦的判断留给了使用者:

  1. 哪几行属于同一处差异?
  2. 应该从哪一行选到哪一行?
  3. 目标一侧是替换、插入还是删除?
  4. 复制完成后,其他行有没有跟着错位?

更麻烦的是,旧版主要按相同行号比较。假设右侧文件中间多了一行,后面的内容即使完全相同,也可能因为行号错位而连续标红。

因此这次不能只把两个按钮挪到差异旁边。程序得先有真正的“差异块”,知道左右各自对应哪些行。

先把三种操作说清楚

正式改代码前,我先确认了三种差异的方向含义。

差异情况点击 点击
左右都有内容,但内容不同用左侧替换右侧用右侧替换左侧
只有左侧有内容把左侧内容插入右侧删除左侧内容
只有右侧有内容删除右侧内容把右侧内容插入左侧

这里最容易误操作的是删除。

比如某几行只存在于左侧,点击 的结果不是“从右侧复制”,而是让左侧与右侧保持一致,也就是删除左侧这几行。如果所有按钮都是同样的蓝色,使用时很容易顺手点错。

最终方案把会产生删除的箭头改成红色。普通替换和插入继续使用蓝色,方向不变,但风险一眼就能看出来。

第一版 UI 方案

编辑器改成左、中、右三栏:

  1. 左边显示左侧文件。
  2. 右边显示右侧文件。
  3. 中间是固定的差异操作轨道。
  4. 每个连续差异块只显示一组
  5. 一侧缺少对应内容时,显示“此处无对应内容”的占位行。
  6. 整个文件覆盖操作移到底部,不再和单个差异块混在一起。

当时先做出的效果图如下:

这张图确认了主要布局,但删除操作还有一个实际问题:如果每次点红色箭头都弹窗确认,连续处理十几个差异块会很烦;如果完全不提示,又容易误删。

最后采用了一个折中方案:

  1. 删除差异块时默认弹出确认。
  2. 确认框里可以勾选“下次不再提示删除确认”。
  3. 这个选择只在本次程序运行期间有效。
  4. 随时可以从“编辑”菜单重新勾选“删除差异块前确认”。
  5. 程序重启后自动恢复默认确认。

这样第一次操作有保护,确认自己理解方向后,也不必反复点击同样的弹窗。

差异算法没有自己硬写

差异块是这次功能的基础。它至少要正确处理:

  1. 普通行修改。
  2. 左侧新增。
  3. 右侧新增。
  4. 文件开头和结尾的差异。
  5. 空文件。
  6. 连续多行修改。
  7. 重复行附近的插入和删除。

这些情况看起来只是比较字符串,但真正麻烦的是行如何对齐。自己写一个“从上往下找不同”的算法,很容易在重复行和中间插入时选错位置。

这次没有继续坚持纯 JDK,而是使用了 java-diff-utils 4.12。它提供了成熟的 Myers 行差异算法,支持 Java 8,许可证是 Apache License 2.0,也没有额外运行时依赖。项目里直接带上 JAR,启动脚本把 lib 加入类路径即可。

这类基础算法没有必要为了“自己写”再造一遍。工具真正需要自己控制的是差异块怎样展示、点击箭头后怎样修改文件,以及怎样防止误操作。

代码先拆模型,再接 Swing

原来的内容编辑器代码都写在主窗口类里。如果继续往里面增加差异算法、对齐行、箭头、撤销和删除确认,文件只会越来越难改。

这次先把核心逻辑拆成几块:

  1. DiffEngine:计算左右文件的差异。
  2. DiffHunk:记录一个连续差异块的类型、位置和内容。
  3. LineDocument:保留文本行、LF/CRLF 和末尾换行状态。
  4. HunkApplyService:把指定差异块应用到左边或右边。
  5. DiffAlignmentService:生成左右等高的显示行和占位行。
  6. DiffEditorFrame:负责三栏界面、按钮、编辑、保存和撤销。

先有模型的好处很直接:差异算法和文件修改可以脱离界面测试。即使 Swing 窗口还没写完,也能先确认点击某个方向后,最终文本到底对不对。

为什么最终用了对齐表格

方案阶段考虑过使用两个 JTextPane,在文本中插入不可保存的占位行,再把中间按钮定位到对应段落。

实际往下推时,这种方式有两个麻烦:

  1. 占位内容混在编辑文档里,保存前必须保证它一定被剔除。
  2. 用户手动增加或删除一行后,按钮位置和占位位置都要重新映射。

最终编辑区改成左右两个对齐表格。每一行背后都保存真实文件行号;没有内容的一侧使用只读占位单元格。中间轨道和左右表格使用同样的固定行高,因此插入、删除后仍然能保持对齐。

真实行可以双击编辑,也可以通过右键菜单插入或删除一行。占位行只负责显示,不会写入文件。

这不是为了把界面做成表格,而是为了明确区分“真实文件内容”和“为了对齐而显示的内容”。

点击一个箭头后发生了什么

为例,实际流程是:

  1. 读取当前差异块在左右文件中的行范围。
  2. 判断操作会产生替换、插入还是删除。
  3. 如果会删除右侧内容,根据当前设置决定是否确认。
  4. 把右侧修改前的文本放入撤销记录。
  5. 只替换当前差异块对应的右侧行。
  6. 重新计算全部差异块和对齐行。
  7. 保持滚动位置,刷新中间箭头。
  8. 标记右侧文件“已修改”,但暂时不写磁盘。

一次差异块操作只产生一条撤销记录,按 Ctrl+Z 可以整体撤回。只有点击保存后,修改才真正写入文件。

手动编辑后不会立即在界面线程里反复计算,而是等待约 300 毫秒,再在后台重新计算差异。这样连续输入时不会每敲一个字都重排整个编辑器。

真实截图还是发现了问题

功能编译通过、测试通过后,我用三类差异生成了一张真实 Swing 窗口截图。

第一张截图里,代码正常显示,但“此处无对应内容”变成了几个方框。原因是占位行错误地沿用了 Consolas,当前系统没有正确回退到中文字库。

最后把代码行继续保留为等宽字体,占位提示单独改成微软雅黑,重新截图后才正常。

代码复查时还发现另一个边界:左右都有内容但行数不同的 CHANGE 差异,也可能产生删除。最初的红色判断只覆盖“仅左侧”和“仅右侧”,会漏掉这种不等长替换。后来把判断改成比较左右差异块行数,并补了一条回归测试。

这两个问题都不是编译器能发现的。一个只能从真实界面看出来,另一个需要把交互语义重新代入边界场景。

最终运行效果

最终编辑器如下:

现在三种差异都能直接处理:

  1. 内容不同:点击方向按钮替换当前块。
  2. 左侧独有:向右插入,或者从左侧删除。
  3. 右侧独有:向左插入,或者从右侧删除。

两侧纵向滚动仍然联动,长代码可以各自横向滚动。整文件复制、分别保存、全部保存和重新加载也都保留了。

相比旧版,最大的变化不是少选了几次文字,而是不用再自己判断目标位置。程序已经把属于同一处的差异放在了一行操作轨道上。

这次实际修改了哪些内容

1. 差异模型

  1. 引入 Myers 行差异算法。
  2. 支持修改、左侧独有、右侧独有三类差异。
  3. 记录左右起止行和差异内容。
  4. 保留 LF、CRLF 和文件末尾换行状态。

2. 编辑器界面

  1. 改成左右文件加中间操作轨道的三栏结构。
  2. 差异行使用红色背景,相同行使用浅绿色背景。
  3. 缺失位置显示不可编辑的占位行。
  4. 每个连续差异块显示一组
  5. 双击真实行可以编辑,右键可以插入或删除行。

3. 操作安全

  1. 删除型箭头标红。
  2. 删除前默认确认。
  3. 支持本次运行期间不再提示。
  4. 支持从“编辑”菜单恢复删除确认。
  5. 每次差异块操作可以通过 Ctrl+Z 撤销。
  6. 未保存关闭和重新加载仍然需要确认。

4. 构建与依赖

  1. 增加 java-diff-utils 4.12
  2. 更新 run.bat 的编译和运行类路径。
  3. 增加第三方依赖说明。
  4. 保持 Java 8 兼容。

5. 测试

  1. 修改、插入、删除差异识别。
  2. 重复行和空文件。
  3. 差异块左右应用结果。
  4. 占位行对齐。
  5. LF、CRLF 和末尾换行。
  6. 不等长修改块的删除提示。
  7. 原有过滤规则回归。
  8. 真实 Swing 窗口截图检查。

最终版提示词

如果要在一个现有 Java Swing 文件对比工具中实现同类功能,可以使用下面这份提示词:

 复制代码请继续开发一个现有的 Java 8 Swing 文件对比工具。工具已经支持文件和目录SHA-256 对比、可折叠目录树、过滤规则、左右同步、F5 刷新、联动滚动和双击打开内容编辑器。本次实现 P0“差异块级双向操作”,替换当前依赖手动选中文字再复制的方式。功能要求:1. 使用可靠的行差异算法识别连续差异块,覆盖 CHANGE、仅左侧、仅右侧。2. 每个差异块记录左右起止行和内容,不能继续按相同行号简单比较。3. 编辑器改成左侧文件、中间差异操作轨道、右侧文件三栏结构。4. 左右显示行必须对齐;一侧缺失内容时显示只读占位行,占位文字绝不能保存。5. 每个连续差异块在中间显示一组 ←、→,不需要先选择文字。6. → 表示让右侧当前差异块与左侧一致;← 表示让左侧与右侧一致。7. 修改、插入、删除三种语义必须正确。任何会减少目标侧行数的操作都属于删除。8. 删除型箭头使用红色,普通替换和插入使用蓝色,并提供清晰的悬浮说明。9. 删除前默认确认,确认框增加“下次不再提示删除确认”。10. 关闭提示只在当前程序会话生效;编辑菜单提供可勾选的    “删除差异块前确认”,程序重启后恢复默认确认。11. 每次差异块操作只修改当前块,不能影响其他差异;操作后重新计算差异。12. 每次差异块操作作为一个撤销单元,支持 Ctrl+Z。13. 保留双击编辑、手动插入删除行、未保存状态、分别保存、全部保存、    重新加载和整文件双向复制。14. 左右纵向滚动保持联动,横向滚动互不影响。15. P0 继续使用 UTF-8,但必须保留 LF/CRLF 和文件末尾换行状态。16. 差异计算放到后台执行,手动编辑使用短延迟合并刷新,避免阻塞 Swing EDT。17. 优先把差异算法、差异块应用和行对齐拆成独立模型,不要继续堆在主窗口类中。18. 引入第三方差异库前检查 Java 8 兼容性、许可证和运行时依赖,并更新启动脚本。19. 增加回归测试,至少覆盖修改、插入、删除、重复行、空文件、文件首尾、    不等长差异、左右应用、占位对齐、LF/CRLF 和末尾换行。20. 完成后编译全部源码和测试,运行真实 Swing 界面并生成截图检查字体、对齐、    箭头颜色、最小窗口和按钮文字。修改前先阅读现有代码和开发计划,给出执行计划、交互方案和 UI 效果图。我确认后再修改正式代码。实现完成后更新 README、开发计划状态和第三方依赖说明。

下一步

P0 已经完成,开发计划中的下一项是 P1:编码与换行保真。

当前编辑器仍然按 UTF-8 读取和保存文件。遇到 GBK、GB2312 或 UTF-16 文件时,打开后可能乱码,直接保存还可能破坏原文件。

下一步需要先做编码识别,再记录每一侧文件的原始编码、BOM 和换行方式,保存时尽量保持不变。同时还要处理识别不确定时的提示,不能只凭一次猜测直接覆盖。

之后再做同步预览和备份。目录同步涉及覆盖文件,真正用于项目之前,最好先明确展示将新增和覆盖哪些内容,并保留失败恢复能力。

最后

这一期终于把开发计划里的第一个核心问题解决了。

以前看到一处差异,要先判断范围、选中文字、找到目标位置,再点复制;现在程序先把差异对齐,操作的人只需要决定方向。

这也是工具从“功能能跑”到“操作顺手”的区别。很多时候并不是少一个按钮,而是程序有没有替使用者完成本来就能自动完成的判断。

不过现在的使用体验仍然谈不上成熟。编辑器目前是行级对比,还没有字符级高亮;常见中文编码没有识别;大文件差异计算、快捷键和差异导航也还有优化空间。

后面会继续按计划往下做,不再临时想到什么就加什么。下一期先处理编码问题,继续记录方案、提示词、实现过程和实际效果。

点击查看更多
推荐专题
热门阅读