java实现文件对比

  • 需求
  • 实现效果
  • 后端代码引入

需求

web项目需要实现文件内容对比功能,开发语言是java,也就是通过java实现类似于svn的文件对比功能

实现效果

效果图如下

后端代码引入

首先引入对比的核心jar包

<!--对比工具依赖--><dependency><groupId>io.github.java-diff-utils</groupId><artifactId>java-diff-utils</artifactId><version>4.9</version></dependency>

页面流程实现,点击列表页按钮 历史版本 查看历史版本记录

历史版本跳转方法

<li><a class="btn btn-info" onclick="getHistoryVersion();" shiro:hasPermission="project:publishCosFiles:history"><i class="fa fa-history"></i> 历史版本</a>
</li>//查看当前目录的历史版本
function getHistoryVersion(){$.modal.openTab('历史版本',prefix + "/getHistoryVersion?platform="+$('#platform').val()+"&title="+$("#title").val());
}

controller方法,接收页面传参跳转到历史版本列表页面

/*** 获取目录历史版本页面*/
@RequestMapping("/getHistoryVersion")
@RequiresPermissions("project:publishCosFiles:history")
public String getHistoryVersion(HttpServletRequest request) throws Exception {String title = request.getParameter("title");String platform = request.getParameter("platform");request.setAttribute("title", title);request.setAttribute("platform", platform);return prefix + "/publishCosFileVersion";
}

历史版本列表页面

列表页面代码 publishCosFileVersion.html

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head><th:block th:include="include :: header('文件版本列表')" /><style>.my-search-collapse {width: 100%;background: #fff;border-radius: 6px;margin-top: 10px;padding-top: 10px;padding-bottom: 6px;box-shadow: 1px 1px 3px rgba(0,0,0,.2);}</style>
</head>
<body class="gray-bg">
<div class="container-div"><div class="row"><div class="col-sm-12 my-search-collapse"><div><div style="color:red;">当前目录:[[${title}]]</div></div></div><div class="col-sm-12 search-collapse"><form id="formId"><div class="select-list"><ul><input type="hidden" id="path" name="path" th:value="${title}"><input type="hidden" id="platform" name="platform" th:value="${platform}"><li>文件名:<input type="text" name="name"/></li><li><input name="createUser" type="hidden" id="createUser"/>操作人:<input id="createUserName" name="createUserName" readonly  type="text" onclick="selectUserDeptTree('createUser','createUserName')" ></li><li>备注信息:<input type="text" name="remark"/></li><li class="input-daterange input-group">修改时间:<input type="text" name="createStartDate" readonly id="createStartDate"/>至<input type="text" name="createEndDate" readonly id="createEndDate"/></li><li><a class="btn btn-primary btn-rounded btn-sm" onclick="search1();"><iclass="fa fa-search"></i>&nbsp;搜索</a><a class="btn btn-warning btn-rounded btn-sm" onclick="reset1();"><iclass="fa fa-refresh"></i>&nbsp;重置</a></li><li style="float: right"><button style="width: 40px;" class="btn btn-default btn-outline" type="button" onclick="search1();" name="refresh" aria-label="刷新" title="刷新"><i class="glyphicon glyphicon-refresh icon-refresh"></i> </button></li></ul></div></form></div><div class="col-sm-12 select-table table-striped"><table id="bootstrap-table" data-mobile-responsive="true"></table></div></div>
</div>
<div th:include="include :: footer"></div>
<script th:inline="javascript">var viewImgFlag = [[${@permission.hasPermi('project:publishCosFiles:showImage')}]];var prefix = ctx + "project/publishFileVersion";$(function() {var options = {url: prefix + "/cmsFileVersionList",modalName: "文件版本",showExport: false,pagination: false,showSearch: false,showToggle: false,showRefresh:false,showColumns:false,sortName:'name',sortOrder:'asc',columns: [{title: '',align: 'center',formatter: function(value, row, index) {var actions = [];//所有的加版本号actions.push('<a class="" href="javascript:" onclick="addChildHtml(\'' + row.name + '\', this,'+row.id+' )"><i class="glyphicon glyphicon-plus icon-plus"></i></a>');return actions.join('');}},{checkbox: true},{field : 'id',title : '主键id',visible: false},{field : 'name',title : '文件名',formatter: function(value, row, index) {var showname = value;if (value.length > 15) {showname = value.substr(0,14)+"...";}var html = "<div title='"+value+"'>"+showname+"</div>";return html;},sortable:true},{field : 'versionNum',title : '版本号',},{field : 'createDate',title : '修改时间',sortable:true},{field : 'size',title : '文件大小',formatter: function(value, row, index) {if(row.delFlag === 1){//  删除的时候大小展示已删除return "已删除";}var fileSize = row.size;if (fileSize != null) {var number1024 = 1<<10;var number1048576 = 1<<20;var number1073741824 = 1<<30;if (fileSize > number1024) {if (fileSize > number1048576) {if (fileSize > number1073741824) {var fixed = (fileSize/number1073741824).toFixed(2);return fixed+"GB";}else {var fixed = (fileSize/number1048576).toFixed(2);return fixed+"MB";}}else {var fixed = (fileSize/number1024).toFixed(2);return fixed+"KB";}}else {return fileSize+"B";}}else {return "-";}}},{field : 'createUserName',title : '修改人',},{field : 'remark',title : '备注信息',formatter: function(value, row, index) {return $.table.tooltip(value);}},{title: '操作',align: 'left',cellStyle: function (value, row, index) {return {css: {"overflow": "hidden", "text-overflow": "ellipsis", "white-space": "nowrap"}}},formatter: function(value, row, index) {var actions = [];var fileType = row.type;if (fileType != null&& ("jpg" == fileType.toLowerCase() || "png" == fileType.toLowerCase() || "gif" == fileType.toLowerCase() || "jpeg" == fileType.toLowerCase())) {actions.push('<a class="btn btn-success btn-xs ' + viewImgFlag + '" href="javascript:void(0)" onclick="viewImage(\'' + row.bakPathPrefix +"/"+ row.bakName +'\')"><i class="fa fa-leaf"></i>预览</a> ');}return actions.join('');}}]};$.table.init(options);initLaydate();});/*账户管理-新增-选择人部门树*/function selectUserDeptTree(treeId,treeName) {// url 可选参数, 其他参数 请自定扩展// permission 权限 0.无权限 1.按照登录人数据权限// showType 展示方式 0.人员 1.人员+工号// checkType 选中类型 0.多选 1.单选// showLevel 展示层级var url = ctx + "system/userDeptTree?showType=1&showLevel=2&checkType=1";var options = {title: '选择部门',width: "500",url: url,callBack: function (index, layero) {// 是否允许选父级var body = layer.getChildFrame('body', index);$("#"+treeId).val(body.find('#ids').val());$("#"+treeName).val(body.find('#names').val());layer.close(index);}};$.modal.openOptions(options);}function initLaydate() {layui.use('laydate', function() {var laydate = layui.laydate;var startDate = laydate.render({elem: '#createStartDate',//max: $('#createEndDate').val(),type: 'datetime',theme: 'molv',trigger: 'click'/*done: function (value, date) {// 结束时间大于开始时间if (value !== '') {endDate.config.min.year = date.year;endDate.config.min.month = date.month - 1;endDate.config.min.date = date.date;} else {endDate.config.min.year = '';endDate.config.min.month = '';endDate.config.min.date = '';}}*/});var endDate = laydate.render({elem: '#createEndDate',//max:$.common.getNowFormatDate(),type: 'datetime',theme: 'molv',trigger: 'click'/*done: function (value, date) {// 开始时间小于结束时间if (value !== '') {startDate.config.max.year = date.year;startDate.config.max.month = date.month - 1;startDate.config.max.date = date.date;} else {startDate.config.max.year = '';startDate.config.max.month = '';startDate.config.max.date = '';}}*/});})}//预览图片function viewImage(filePath) {var url = ctx + 'project/publishCosFiles/showImage?filePath=' + filePath;$.modal.open("图片预览", url , '600', '500',function (index) {layer.close(index);});}//加载当前文件的历史版本function addChildHtml(name,tdThis,id) {
//      判断是否是加号,加号的话展开并加载子类,如果是减号的话则删除掉子类if ($(tdThis).children('i').hasClass('glyphicon-plus')) {
//        加载子类数据var html = "";var formData = {"path":$("#path").val(),"platform":$("#platform").val(),"name":name};$.ajax({url: prefix + "/getOneFileHistory",type: 'post',dataType: "json",data: formData,success: function(result) {if(result.code == web_status.SUCCESS){$.each(result.data,function (i,k) {html += '<tr child-index="'+i+'" class="child-tr pid-'+id+'">';html +='<td style="text-align: center; "/>';html +='<td/>';if(k.name==null){html +='<td style="">-</td>';}else {var showname = k.name;if (showname.length > 15) {showname = showname.substr(0,14)+"...";}html += '<td title="'+k.name+'">'+showname+'</td>';}html +='<td style="">'+k.versionNum+'</td>';html +='<td style="">'+k.createDate+'</td>';var fileSize = k.size;if (fileSize != null) {var number1024 = 1<<10;var number1048576 = 1<<20;var number1073741824 = 1<<30;if (fileSize > number1024) {if (fileSize > number1048576) {if (fileSize > number1073741824) {var fixed = (fileSize/number1073741824).toFixed(2);html +='<td style="">'+fixed+'GB</td>';}else {var fixed = (fileSize/number1048576).toFixed(2);html +='<td style="">'+fixed+'MB</td>';}}else {var fixed = (fileSize/number1024).toFixed(2);html +='<td style="">'+fixed+'KB</td>';}}else {html +='<td style="">'+fileSize+'B</td>';}}else {html +='<td style="">-</td>';}html +='<td style="">'+k.createUserName+'</td>';html +='<td style="">'+$.table.tooltip(k.remark);+'</td>';html +='<td style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; ">';var fileType = k.type;if (fileType != null&& ("jpg" == fileType.toLowerCase() || "png" == fileType.toLowerCase() || "gif" == fileType.toLowerCase() || "jpeg" == fileType.toLowerCase())) {html +='<a class="btn btn-success btn-xs ' + viewImgFlag + '" href="javascript:void(0)" onclick="viewImage(\'' + k.bakPathPrefix +"/"+ k.bakName +'\')"><i class="fa fa-leaf"></i>预览</a> ';}if(i!=0){//不是第一个的时候加还原html +='<a class="btn btn-warning btn-xs " href="javascript:void(0)" onclick="rollbackFile('+k.id+')">';html +='<i class="fa fa-mail-reply"/>还原</a> ';}else {// 是第一个的时候如果是删除的加还原if(k.delFlag === 1){html +='<a class="btn btn-warning btn-xs " href="javascript:void(0)" onclick="rollbackFile('+k.id+')">';html +='<i class="fa fa-mail-reply"/>还原</a> ';}}if (fileType != null && ("html" == fileType.toLowerCase() || "shtml" == fileType.toLowerCase() || "css" == fileType.toLowerCase() ||"js" == fileType.toLowerCase()|| "txt" == fileType.toLowerCase())) {html +='<a class="btn btn-info btn-xs " href="javascript:void(0)" onclick="comparedFile('+k.id+')">';html +='<i class="fa fa-exchange"/>对比</a>';}html +='</td>';html +='</tr>';});$(tdThis).parent().parent().after(html);}else{if("未登录或登录超时。请重新登录"==res.msg){window.location=ctx+"login";}else {$.modal.alertError(result.msg);}}}});
//        写入之类成功之后在去掉加号等样式,防止出错$(tdThis).children('i').removeClass('glyphicon-plus');$(tdThis).children('i').removeClass('icon-plus');$(tdThis).children('i').addClass('glyphicon-minus');$(tdThis).children('i').addClass('icon-minus');}else {
//        减号的时候点击将子类数据移除,然后将减号变加号$('.pid-'+id+'').remove();$(tdThis).children('i').removeClass('glyphicon-minus');$(tdThis).children('i').removeClass('icon-minus');$(tdThis).children('i').addClass('glyphicon-plus');$(tdThis).children('i').addClass('icon-plus');}}//还原文件的方法function rollbackFile(id){$.modal.confirm("确认要还原该文件吗?", function() {var url =  prefix + "/rollbackFile";var data = { "id": id };$.operate.submit(url, "post", "json", data,function () {$.table.search();});});}//对比选择function comparedFile(id){$.modal.openTab('对比选择',prefix + "/selectCompared/?id="+id);}function search1() {var start = $("#createStartDate").val();var end = $("#createEndDate").val();var startdate = new Date(start);var enddate = new Date(end);if (startdate.getTime() > enddate.getTime()) {$.modal.alertError("开始时间不能大于结束时间");return false;}$.table.search();}function reset1() {$("#createUser").val("");$.form.reset();}
</script>
</body>
</html>

点击列表页之后跳转文件对比controller方法

@RequestMapping("/comparedThisFile")
public String comparedThisFile(HttpServletRequest request, ModelMap mmap)
{String text1path = null;String text2path = null;//String htmlPath = null;String platform = request.getParameter("platform");try {String leftId = request.getParameter("leftId");String rightId = request.getParameter("rightId");String profile = ConfigConstant.cosTempPath;PublishFileVersion left = publishFileVersionService.selectPublishFileVersionById(Long.parseLong(leftId));
//      获取左边文件路径String bakpath = left.getBakPathPrefix();String bakname = left.getBakName();//file.text_0String filename = left.getName();String downname = filename +"_"+left.getVersionNum();if (filename.contains(".")) {downname = filename.replace(".","_"+left.getVersionNum()+".");}if(left.getObfuscateFlag()==1){
//        混淆的时候文件名用混淆的那个名字bakname = left.getObfuscateSourceName();}String leftkey = bakpath + bakname;PublishFileVersion right = publishFileVersionService.selectPublishFileVersionById(Long.parseLong(rightId));
//      获取右边文件路径String bakpath2 = right.getBakPathPrefix();String bakname2 = right.getBakName();//file.text_0String filename2 = right.getName();String downname2 = filename2 +"_"+right.getVersionNum();if (filename2.contains(".")) {downname2 = filename2.replace(".","_"+right.getVersionNum()+".");}if(right.getObfuscateFlag()==1){
//        混淆的时候文件名用混淆的那个名字bakname2 = right.getObfuscateSourceName();}String rightkey = bakpath2 + bakname2;if (Constants.Platform.COS.getValue().equals(Integer.valueOf(platform))) {CosClientUtil cosClientUtil = new CosClientUtil();try {//下载到服务器text1path = profile + downname;cosClientUtil.download(leftkey, text1path);} catch (InterruptedException e) {e.printStackTrace();}try {//下载到服务器text2path = profile + downname2;cosClientUtil.download(rightkey, text2path);} catch (InterruptedException e) {e.printStackTrace();}}else {text1path = bakpath+File.separator+bakname;text2path = bakpath2+File.separator+bakname2;}List<String> diffString = DiffHandleUtils.diffString(text1path,text2path,downname,downname2);//System.out.println("======diff::::::"+diffString);//在服务器生成一个diff.html文件,打开便可看到两个文件的对比//htmlPath = profile + "compareresult.html";String string = DiffHandleUtils.generateDiffString(diffString);//System.out.println("======res::::::"+string);mmap.put("right", string);}catch (Exception e) {e.printStackTrace();}finally {if (Constants.Platform.COS.getValue().equals(Integer.valueOf(platform))) {//删除下载的临时文件if (StringUtils.isNotEmpty(text1path)) {boolean delete = new File(text1path).delete();}if (StringUtils.isNotEmpty(text2path)) {boolean delete = new File(text2path).delete();}}}return  prefix+"/newComparedFile";
}

文件对比工具类主要方法 DiffHandleUtils.java

package com.dongao.project.utils;import com.github.difflib.UnifiedDiffUtils;
import com.github.difflib.patch.Patch;import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;/*** @Author zhangw* @Date 2022/4/21 18:04* @Version 1.0*/
public class DiffHandleUtils {/*** 对比两文件的差异,返回原始文件+diff格式** @param original 原文件内容* @param revised  对比文件内容*/public static List<String> diffString(List<String> original, List<String> revised) {return diffString(original, revised, null, null);}/*** 对比两文件的差异,返回原始文件+diff格式** @param original         原文件内容* @param revised          对比文件内容* @param originalFileName 原始文件名* @param revisedFileName  对比文件名*/public static List<String> diffString(List<String> original, List<String> revised, String originalFileName, String revisedFileName) {originalFileName = originalFileName == null ? "原始文件" : originalFileName;revisedFileName = revisedFileName == null ? "对比文件" : revisedFileName;//两文件的不同点Patch<String> patch = com.github.difflib.DiffUtils.diff(original, revised);//生成统一的差异格式List<String> unifiedDiff = UnifiedDiffUtils.generateUnifiedDiff(originalFileName, revisedFileName, original, patch, 0);if (unifiedDiff.size() == 0) {//如果两文件没差异则插入如下unifiedDiff.add("--- " + originalFileName);unifiedDiff.add("+++ " + revisedFileName);unifiedDiff.add("@@ -0,0 +0,0 @@");} else if (unifiedDiff.size() >= 3 && !unifiedDiff.get(2).contains("@@ -1,")) {//如果第一行没变化则插入@@ -0,0 +0,0 @@unifiedDiff.add(2, "@@ -0,0 +0,0 @@");}//原始文件中每行前加空格List<String> original1 = original.stream().map(v -> " " + v).collect(Collectors.toList());//差异格式插入到原始文件中return insertOrig(original1, unifiedDiff);}/*** 对比两文件的差异,返回原始文件+diff格式** @param filePathOriginal 原文件路径* @param filePathRevised  对比文件路径*/public static List<String> diffString(String filePathOriginal, String filePathRevised,String originalName,String revisedName) {//原始文件List<String> original = null;//对比文件List<String> revised = null;File originalFile = new File(filePathOriginal);File revisedFile = new File(filePathRevised);try {original = Files.readAllLines(originalFile.toPath());revised = Files.readAllLines(revisedFile.toPath());} catch (IOException e) {e.printStackTrace();}return diffString(original, revised, originalName, revisedName);}/*** 通过两文件的差异diff生成 html文件,打开此 html文件便可看到文件对比的明细内容** @param diffString 调用上面 diffString方法获取到的对比结果* @param htmlPath   生成的html路径,如:/user/var/mbos/ent/21231/diff.html* HTML输出接受一个Javascript对象,该对象可能有以下配置项:** inputFormat: 输入数据的格式: 'diff' 或者 'json', 默认是'diff'* outputFormat: 输出数据的格式: 'line-by-line' 或者 'side-by-side', 默认是'line-by-line'* showFiles: 在对比之前查看文件列表,true 或者false,默认是false* matching: 匹配level: 'lines'用于匹配行, 'words' 用于匹配行和单词,或者设置为'none',默认为none* matchWordsThreshold: 单词相似度下限, 默认是0.25* matchingMaxComparisons: 为了匹配一组变化最多执行的比较次数,默认是2500* maxLineLengthHighlight: 如果行数小于此值,则仅仅执行差异突出显示,默认是10000* templates: 使用预备好的编译的模板替换部分html的对象。* rawTemplates: 具有原始未编译模板的对象替换部分html。* 更多参考 https://github.com/rtfpessoa/diff2html/tree/master/src/templates*/public static void generateDiffHtml(List<String> diffString, String htmlPath) {StringBuilder builder = new StringBuilder();for (String line : diffString) {builder.append(line);builder.append("\n");}String template = "<!DOCTYPE html>\n" +"<html lang=\"en-us\">\n" +"  <head>\n" +"    <meta charset=\"utf-8\" />\n" +"    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.1/styles/github.min.css\" />\n" +"     <link rel=\"stylesheet\" type=\"text/css\" href=\"https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css\" />\n" +"    <script type=\"text/javascript\" src=\"https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js\"></script>\n" +"  </head>\n" +"  <script>\n" +"    const diffString = `\n" +"temp\n" +"`;\n" +"\n" +"\n" +"     document.addEventListener('DOMContentLoaded', function () {\n" +"      var targetElement = document.getElementById('diffElement');\n" +"      var configuration = {\n" +"        drawFileList: true,\n" +"        fileListToggle: false,\n" +"        fileListStartVisible: false,\n" +"        fileContentToggle: false,\n" +"        matching: 'words',\n" +"        outputFormat: 'side-by-side',\n" +"        synchronisedScroll: true,\n" +"        highlight: true,\n" +"        renderNothingWhenEmpty: true,\n" +"      };\n" +"      var diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);\n" +"      diff2htmlUi.draw();\n" +"      diff2htmlUi.highlightCode();\n" +"    });\n" +"  </script>\n" +"  <body>\n" +"    <div id=\"diffElement\"></div>\n" +"  </body>\n" +"</html>";String string = builder.toString();string = string.replace("/", "\\/");template = template.replace("temp", string);FileWriter f = null; //文件读取为字符流try {f = new FileWriter(htmlPath);BufferedWriter buf = new BufferedWriter(f); //文件加入缓冲区buf.write(template); //向缓冲区写入buf.close(); //关闭缓冲区并将信息写入文件f.close();} catch (IOException e) {e.printStackTrace();}}/*** 通过两文件的差异diff生成 string,打开此 html文件便可看到文件对比的明细内容* @param diffString* @return*/public static String generateDiffString(List<String> diffString) {StringBuilder builder = new StringBuilder();builder.append("`");for (String line : diffString) {//对比页面开始符号冲突if (line.contains("`")) {line = line.replace("`","\\`");}//</script>结束标志</冲突if (line.contains("</")) {line = line.replace("</", "<\\/");}//正则\冲突if (line.contains("\\") && line.contains("^")) {line = line.replace("\\", "\\\\");}//页面取值冲突 ${}if (line.contains("${")) {line = line.replace("${", "$\\{");}builder.append(line);builder.append("\n");}builder.append("`");String string = builder.toString();return string;}//统一差异格式插入到原始文件public static List<String> insertOrig(List<String> original, List<String> unifiedDiff) {List<String> result = new ArrayList<>();//unifiedDiff中根据@@分割成不同行,然后加入到diffList中List<List<String>> diffList = new ArrayList<>();List<String> d = new ArrayList<>();for (int i = 0; i < unifiedDiff.size(); i++) {String u = unifiedDiff.get(i);if (u.startsWith("@@") && !"@@ -0,0 +0,0 @@".equals(u) && !u.contains("@@ -1,")) {List<String> twoList = new ArrayList<>();twoList.addAll(d);diffList.add(twoList);d.clear();d.add(u);continue;}if (i == unifiedDiff.size() - 1) {d.add(u);List<String> twoList = new ArrayList<>();twoList.addAll(d);diffList.add(twoList);d.clear();break;}d.add(u);}//将diffList和原始文件original插入到result,返回resultfor (int i = 0; i < diffList.size(); i++) {List<String> diff = diffList.get(i);List<String> nexDiff = i == diffList.size() - 1 ? null : diffList.get(i + 1);//含有@@的一行String simb = i == 0 ? diff.get(2) : diff.get(0);String nexSimb = nexDiff == null ? null : nexDiff.get(0);//插入到resultinsert(result, diff);//解析含有@@的行,得到原文件从第几行开始改变,改变了多少(即增加和减少的行)Map<String, Integer> map = getRowMap(simb);if (null != nexSimb) {Map<String, Integer> nexMap = getRowMap(nexSimb);int start = 0;if (map.get("orgRow") != 0) {start = map.get("orgRow") + map.get("orgDel") - 1;}int end = nexMap.get("revRow") - 2;//插入不变的insert(result, getOrigList(original, start, end));}if (simb.contains("@@ -1,") && null == nexSimb) {insert(result, getOrigList(original, 0, original.size() - 1));} else if (null == nexSimb && map.get("orgRow") < original.size()) {insert(result, getOrigList(original, map.get("orgRow"), original.size() - 1));}}return result;}//将源文件中没变的内容插入resultpublic static void insert(List<String> result, List<String> noChangeContent) {for (String ins : noChangeContent) {result.add(ins);}}//解析含有@@的行得到修改的行号删除或新增了几行public static Map<String, Integer> getRowMap(String str) {Map<String, Integer> map = new HashMap<>();if (str.startsWith("@@")) {String[] sp = str.split(" ");String org = sp[1];String[] orgSp = org.split(",");//源文件要删除行的行号map.put("orgRow", Integer.valueOf(orgSp[0].substring(1)));//源文件删除的行数map.put("orgDel", Integer.valueOf(orgSp[1]));String[] revSp = org.split(",");//对比文件要增加行的行号map.put("revRow", Integer.valueOf(revSp[0].substring(1)));map.put("revAdd", Integer.valueOf(revSp[1]));}return map;}//从原文件中获取指定的部分行public static List<String> getOrigList(List<String> original1, int start, int end) {List<String> list = new ArrayList<>();if (start <= end && end < original1.size()) {for (; start <= end; start++) {list.add(original1.get(start));}}return list;}
}

返回页面展示结果如开始,newComparedFile.html 页面代码

<!DOCTYPE html>
<html lang="en-us">
<head><meta charset="utf-8" /><link rel="stylesheet" type="text/css" th:href="@{/css/github.min.css}"/><link rel="stylesheet" type="text/css" th:href="@{/css/diff2html.min.css}"/><script type="text/javascript" th:src="@{/js/diff2html-ui.min.js}"></script><script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>
</head>
<script>const diffString = [(${right})];document.addEventListener('DOMContentLoaded', function () {var targetElement = document.getElementById('diffElement');var configuration = {//在diff之前显示文件列表:true或false,默认值为truedrawFileList: true,//允许切换文件摘要列表:true或false,默认值为truefileListToggle: false,//选择文件摘要列表是否开始可见:true或false,默认值为falsefileListStartVisible: false,//允许切换每个文件内容:true或false,默认值为truefileContentToggle: false,//匹配level: 'lines'用于匹配行, 'words' 用于匹配行和单词,或者设置为'none',默认为nonematching: 'words',//输出数据的格式: 'line-by-line' 或者 'side-by-side', 默认是'line-by-line'outputFormat: 'side-by-side',synchronisedScroll: true,highlight: true,renderNothingWhenEmpty: true,};var diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);diff2htmlUi.draw();diff2htmlUi.highlightCode();var texts = $(".d2h-code-wrapper").find("td[class='d2h-info']").find("div");if (texts.length) {$.each(texts,function (index,value) {var _this = $(this);//console.log(_this.text())_this.text("");});}});
</script>
<body>
<div id="diffElement"></div>
</body>
</html>

为了更方便大家测试,这里我补充一个测试类CompareTest.java代码,方便大家测试

package com.dongao;import java.io.*;
import java.util.List;/*** @Description TODO* @Author P001* @Date 2022/4/21 16:37* @Version 1.0*/
class CompareTest {//E:\data\webapps\wwwroot_release\dazx\ei_bak\costempprivate static String path ="E:\\data\\webapps\\wwwroot_release\\dazx\\ei_bak\\costemp\\test"+System.currentTimeMillis()+".html";public static void main(String[] args) throws IOException {/*DiffContent.diff();ShowDiff.show(path);*///对比 F:\n1.txt和 F:\n2.txt 两个文件,获得不同点List<String> diffString = DiffHandleUtils.diffString("E:\\data\\webapps\\wwwroot_release\\dazx\\ei_bak" +"\\costemp\\main0.html","E:\\data\\webapps\\wwwroot_release\\dazx\\ei_bak\\costemp\\main1.html");//在F盘生成一个diff.html文件,打开便可看到两个文件的对比DiffHandleUtils.generateDiffHtml(diffString,path);System.out.println("success");}}

参考文章:https://developer.aliyun.com/article/901714

java实现文件对比相关推荐

  1. java大批量文件对比_推荐 | 这 6 个代码对比工具用过的都说好!

    文章字数:700 干货指数:⭐⭐⭐⭐⭐ 导读:在程序开发的过程中,需要经常对源代码以及库文件进行代码对比,给大家推荐6个常用的代码比较工具. 01WinMerge WinMerge是一款运行于Wind ...

  2. java实现文件对比_【代码】Java比较文件夹文件

    有一款文件比较软件Winmerge的文件夹比较功能比较少,只能比较当前目录下的文件数和文件差别. 但由于需要,查看两个类似的目录中,其中一个少了那些文件.所以就自己写了个脚本,来遍历. 代码如下,由于 ...

  3. Android 反编译 -smali文件对比java文件

    smali文件对比java文件     .class        :类名     .super        :父类     .source        :源文件名     .implements ...

  4. java 读取文件 效率_Java 逐行读取文本文件的几种方式以及效率对比

    前言 上周负责的模块中需要逐行读取文件内容, 写完之后对程序执行效率不太满意, 索性上网查了一下 Java 逐行读取文件内容的各种方法, 并且简单地比对了一下执行效率. 在此记录, 希望能够帮到有需要 ...

  5. java文件对比7,一个线程读一个线程写、返回给前端进度条数据

    java文件对比 controller Service Serviceimpl 读取文件多线程工具类 对比文件多线程工具类 控制台结果 返回结果 进度条结果 个人总结 这个其实写的是有点问题的,想的是 ...

  6. Java内存泄露和内存溢出、JVM命令行工具、.JDK可视化工具、Java Class文件

    1.Java内存泄露和内存溢出对比 1.1 Java 内存泄露 内存泄露是指一个不再被程序使用的对象或变量还在内存中占用空间. 1.1.1判断内存空间是否符合垃圾回收的标准 在Java语言中,判断一个 ...

  7. JVM详解之:java class文件的密码本

    文章目录 简介 一个简单的class ClassFile的二进制文件 class文件的密码本 magic version 常量池 描述符 access_flags this_class和super_c ...

  8. Atitit。DD dragdrop拖拽功能c#.net java swing的对比与实现总结

    Atitit.D&D drag&drop拖拽功能c#.net java swing的对比与实现总结 1. 实现一个D&D操作一般包括三个步骤: 1 2. .net黑头的拖曳机制 ...

  9. Java本地文件操作

    概述:Java本地文件操作,涉及到文件/文件夹的创建,文件/文件夹属性的读取与设置,文件/文件夹的重命名,目录结构的遍历,以及文件内容的读取与写入. File属于java.io.File. ---在E ...

  10. java在文件里搜字段_Java 如何找出两个文本文件中有相同字段的行

    Java有什么方便的类库做文件对比吗?比如:文件Old.txt和New.txt,第一行是列名,需要取出文件中Name字段相同的内容.部分数据如下: Old.txt New.txt Name   Dep ...

最新文章

  1. Prim算法生成迷宫
  2. 【Android 应用开发】 FastJson 使用详解
  3. 一步一步实现iOS QQ第三方登录
  4. 从Setting.settings到Resource.resx
  5. gin-vue-admin菜单配置教程:父子菜单
  6. onTouchEvent
  7. centos7不识别固态硬盘_固态硬盘分区与不分区哪个好【详细介绍】
  8. python android 库_Python库
  9. TCP四种定时器--学习笔记
  10. IT网络通信大变革时代来临 2016中国极客大奖为您找到风向标
  11. JavaScript 经典设计模式
  12. @autowired注解注入为null_Spring @Autowired 注解自动注入流程是怎么样?
  13. IDispatch接口原理与应用
  14. 实验二线性表的链式存储结构
  15. 油猴插件安装以及好用的脚本推荐 包含电脑版本和手机版本
  16. 如何购买银行理财子公司的理财产品?
  17. 听别人的故事探索属于自己的方法
  18. python爬取都挺好影视评论,看看大家的共鸣度有多强?
  19. 多项式定理【OI Pharos 6.2.2】
  20. 【C语言】转义字符\xhh和\ddd到底如何判断?被兔子个数支配的恐惧你也有吗?(每日小细节001)

热门文章

  1. 26款Java开源项目,劝你千万别错过,适合所有程序员
  2. 电子设计教程9:Boost升压电路(MC34063)
  3. 分享一个响应式电商网站前端模板
  4. java 进销存系统_java进销存系统(含数据库)
  5. Gliffy Diagrams(在线绘图)
  6. ➤mobi➢azw3➢epub⇨电子书阅读器 转换器
  7. 怎么注册DLL到注册表
  8. HTML_BOM-01
  9. EXCEL常用函数汇总
  10. java 车牌识别系统_java车牌识别系统 自动识别车牌系统的工作原理