精华内容
下载资源
问答
  • 文件对比
    2021-09-05 14:00:46

            ExamDiff Pro 是一款优秀的可视化电脑文件对比工具和目录比较合并工具,能帮助用户快速比对文件内容、文件夹、Office文档(Word、Excel和PDF文档)、zip压缩文档以及远程计算机上面等多种文件的差异之处,并用不同的颜色加以标识,同时还可以使用内置的文字编辑器来直接编辑文本内容,中英文都可以兼容使用,ExamDiff Pro支持二进制比较准确比较可执行文件、通过内置插件将本地文件夹与FTP服务器上的文件夹进行比较、通过内置插件比较Word、Excel和PDF文档、通过语法高亮显示您的代码结构、创建目录快照以供将来比较和存档、在用户PC和外接媒体之间同步文件和文件夹、执行代码审查并与您的同事共享差异报告,、使用双向和三向差异和合并合并不同的文件版本以及使用内置Shell 扩展与Windows资源管理器进行比较,可谓是最好用的文件对比工具之一,如果大家需要一款超强且靠谱的电脑文件内容对比工具的话,威航软件园推荐大家试试ExamDiff Pro吧,当然了Beyond Compare和IDM UltraCompare也是非常出色的文件比较工具了,大家都对比测试下吧。

    电脑文件对比工具ExamDiff Pro

     
                    对于开发者来说,ExamDiff Pro支持跟踪文件和文件夹中的更改、执行代码审查、使用两路和三路diff和merge轻松合并不同版本的文件、与您的同事共享 HTML 和打印的差异报告、将本地网站与 FTP 服务器进行比较(使用 FTP 插件)、忽略编程语言注释,只关注源代码中最重要的方面、通过语法高亮显示代码的不同方面、使用内置二进制比较比较可执行文件(DLL、EXE 等)

    电脑文件对比工具ExamDiff Pro

     
                    对于普通电脑用户则可以利用ExamDiff Pro进行快速浏览差异、在自己的和外部媒体之间同步文件和目录、创建目录快照以供将来比较和存档、通过将文件与以前的版本进行比较来快速查找和撤消错误、轻松拖放文件和目录、使用内置Shell扩展与Windows资源管理器进行比较,测试人员通过ExamDiff Pro将测试结果与基线进行比较来验证测试结果,将测试比较结果保存到报告中,作家或者白领办公用户则可以使用ExamDiff Pro内置文本编辑器在比较窗口中编辑您的文档、使用同步自动换行来比较文档段落、使用插件比较 Word、Excel 和 PDF 文档。

    电脑文件对比工具ExamDiff Pro

     

    更多相关内容
  • 文件对比

    2019-03-25 01:17:15
    NULL 博文链接:https://rooi.iteye.com/blog/1142014
  • 文本文件在线对比,方便又快捷,支持各种网页嵌入
  • 文件比较

    2018-04-16 16:08:40
    很好的文件比较器可以在编码的过程中 比较两个文件 的不同 特别社和初学者找错 附带颜色采集起 特别社和前端的朋友 哈哈哈
  • 文件对比

    2018-10-10 09:18:47
    可用于文件之间的对比,例如.java文件间查看代码内容有哪些不同之处
  • 二进制文件比较工具,可以支持两个pe文件的分析对比,内容是否有差异。可以快速定位出两个dll/exe是不是被修改多
  • BIN文件比较工具

    2018-10-31 16:48:23
    这个工具是比较二进制代码的利器。好用看得见。比其他的软件好用
  • 文件比较工具,可以对比不同版本文件的差异
  • bin文件对比工具

    2017-03-11 16:03:35
    快速对比两个bin文件不同点
  • java文件对比工具

    2018-03-27 17:40:21
    文件对比工具 JAVA JAVA文件对比 工具 对比工具 文件对比工具 JAVA JAVA文件对比 工具 对比工具 文件对比工具 JAVA JAVA文件对比 工具 对比工具
  • 文件对比工具,可以比对整个项目代码,可以整个文件目录
  • 代码对比分析利器,免安装,免破解,win10 64位 win7 64 位下亲测可用
  • Beyond Compare是一款,不可多得的专业级,文件夹和文件对比工具,产品可以很方便地对比出,两个文件夹或者文件的不同之处,并把相差的每一个字节,用颜色加以表示,查看方便

    不管是在办公还是学习的过程中

    难免遇到一些

    相似度较高而又有区别的文件

    如果需要分辨

    那就需要用到文件对比工具了

    Beyond Compare是一款

    不可多得的专业级

    文件夹和文件对比工具

    产品可以很方便地对比出

    两个文件夹或者文件的不同之处

    并把相差的每一个字节

    用颜色加以表示,查看方便

    一、开发商介绍

    Scooter Software是一家位于美国威斯康星州麦迪逊市的独立私营软件公司。

    公司的开发和销售的旗舰产品Beyond Compare,是一款适用于Windows、macOS和Linux平台,全方位、简洁实用专业的文件对比工具。

    从普通的个体开发人员,到世界500强的公司,Beyond Compare在世界各地拥有100万+用户,从26年前产品发布以来,Beyond Compare一直领先于文件对比工具市场。

    二、多方面产品功能

    文本比较

    这是两个源代码文件的比较。具体差异用红色文字标注,整行以浅红色背景表示存在差异。装订线按钮和热键可让您快速将代码段从一侧复制到另一侧。

    三向文本合并

    这是顶部的三个文件和底部的合并、可编辑输出的比较。中心文件是后面两个版本的共同祖先。左右变化会自动包含在输出中。

    表比较

    可以在表比较会话中逐个单元地比较分隔的数据文件。数据可以按关键字段排序和对齐,不重要的列可以忽略。

    图片比较

    图片比较视图并排显示图像,并突出显示它们的差异。可以比较各种类型的图像文件。

    文件夹比较

    以熟悉的Explorer风格并排比较文件夹。差异以颜色突出显示。

    三向文件夹合并

    三向合并现在扩展到文件夹。将独立更改与共同祖先进行比较,以快速将您的更改与其他人的更改合并。它将您的自定义设置合并到新版本中变得轻而易举。

    十六进制比较

    十六进制比较视图在典型的十六进制转储布局中逐字节显示差异。

    注册表比较

    注册表比较视图比较本地和远程实时注册表以及注册表导出。

    可执行比较

    版本比较视图比较可执行文件(例如 .exe 和 .dll)并显示版本信息的差异。版本比较是Windows功能。

    MP3比较

    MP3比较视图比较mp3文件,显示标签的差异。

    三、随时随地访问数据

    多平台使用

    Beyond Compare可以在任何地方使用,在Windows、Linux和现在的macOS上。快速,具有原生外观和感觉,并针对每个平台进行了增强,能够完成您需要做的一切。

    压缩

    Zip文件和其他存档类型可以就地扩展以比较和更新其内容,就像任何其他文件夹一样容易。它可以处理许多流行的格式,包括tar、gzip、bzip2、Microsoft CAB、WinRAR,以及适用于Windows的v4、Zipx、7-zip和IMG/ISO磁盘映像的新版本。

    FTP、SFTP、FTPS

    更新您的网站或进行偏移备份;您不需要单独的FTP客户端。Beyond Compare可以连接到FTP、FTP over SSL和SFTP (SSH)服务器,并使用您习惯使用的相同命令比较、合并或同步更改。它保存了配置文件以加快访问速度,并支持多个同时连接以加快速度。

    媒体设备

    插入您的相机、MP3播放器或Android手机并立即访问它,就像任何其他驱动器一样。同步您的音乐。复制你的照片。保存你的高分。

    远程比较

    直接将您的本地Subversion工作目录与远程存储库进行比较,而无需创建第二次签出。还支持多个分支和过去的修订,以使合并分支变得轻而易举。

    云储存

    组织您的云存储,无论是在WebDAV服务器还是Amazon S3上。当您没有安装完整的客户端时,从Dropbox获取一些文件。无论您的数据在哪里,Beyond Compare都可以轻松实现。

    四、新版本功能

    新的主页视图

    新的主视图添加了会话搜索和Web资源。使用屏幕控件更易于管理布局。

    临时不重要文件

    现在可以更轻松地在文本比较中定义不重要的文本。直接从“规则”对话框定义不重要的术语,而不必编辑文件格式。

    大图片比较

    图片比较具有全新外观,具有自动缩放、像素级细节和简化控件。容差比较模式使用灰度来显示图像以及差异。它也更快,使用更少的内存,并支持其他图像格式。

    带有搜索功能的首选项对话框

    重新组织的选项对话框包括用于快速查找特定设置的搜索功能。无需先打开视图即可自定义所有比较类型的命令。

    识别二维码关注我们

    如果您有任何产品疑问,请随时访问上海道宁官网向我们咨询

    我们会根据您的需求,提供相应的软件版本推荐

    一站式查询和采购平台

    展开全文
  • 支持文件夹 、文件内容对比,绿色版,无恶意插件无毒无广告,放心使用。
  • 文件比较工具winmerge

    2019-03-22 17:07:58
    官网地址:http://winmerge.org/downloads/?lang=en 20190322
  • 这是一款非常好用的PDF文件比较工具软件,可以比较两个PDF文件的文字和布局方面的不同,在不同的地方会用特殊颜色来进行注释,该pdf对比工具对于我们来说非常有用,比如php代码升级之后,有些地方会有改进,如果你想...
  • 比较文件的实用工具,可以对各种文件进行分析对比,比如代码文件或者文本文件
  • IDEA从零到精通(34)之IDEA 强大的文件对比功能

    作者简介

    作者名:编程界明世隐
    简介:CSDN博客专家,从事软件开发多年,精通Java、JavaScript,博主也是从零开始一步步把学习成长、深知学习和积累的重要性,喜欢跟广大ADC一起打野升级,欢迎您关注,期待与您一起学习、成长、起飞!

    引言

    我本来是一直用eclipse和myeclipse的老程序员了,很多我的粉丝小伙伴都说他们要用idea,问我怎么不用idea,其实明哥觉得用啥开发工具都不是重点,重点是要跟着明哥多学Java知识、多练习,但是作为一个宠粉的人,我怎么能拒绝粉丝的要求呢,于是我偷偷的去学习了一波(拿来吧你),然后就写了这个系列,希望小伙伴们能有所收获,明哥会努力更新的。

    导航

    ✪ IDEA从零到精通目录索引
    ◄上一篇【33】IDEA优化导包(自动导入包、删除包)
    ►下一篇【35】各种搜索功能

    概述

    对于程序员来说,文件对比其实我们经常用,比如我们经常利用SVN比较多个版本的代码。
    有时候我们需要对比两个代码有无异同的时候,我们自然会想到用工具,比如:Beyond Compare
    在这里插入图片描述
    实际上IDEA自带了非常方便的文件比较功能,我们利用他可以很方便的比较文件的异同。

    操作步骤

    1. 创建2个用来比较的类(Test和Test2类),如下:
    import vo.User;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Test {
        public static void main(String[] args) {
            List list = new ArrayList();
    
            User user = new User();
        }
    }
    
    import vo.User;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Test2 {
        public static void main(String[] args) {
            List  list = new ArrayList();
            System.out.println(2222);
            User user = new User();
            System.out.println(111);
        }
    }
    
    1. 同时选中这2个类

    选中Test类后按住ctrl不放,鼠标左键点击Test2类。

    在这里插入图片描述

    1. 右键选择compare files

    在这里插入图片描述

    1. 进入文件比较窗口

    在这里插入图片描述

    1. 设置高亮显示

    我喜欢设置highlight words,让不同的显示

    在这里插入图片描述
    效果如下:
    在这里插入图片描述

    1. 设置忽略空格

    没设置之前,空格也会被当成有差异的

    在这里插入图片描述
    设置方式
    在这里插入图片描述
    设置之后,空格会被忽略
    在这里插入图片描述

    1. 接受差异

    有的差异你认为可以接受的直接点击双箭头,差异就会移动过去。

    在这里插入图片描述

    1. 直接在比较窗口修改文件

    在比较窗口修改的后,会直接反映在类中,就等于是直接修改类。

    在这里插入图片描述

    1. 切换混合视图

    在这里插入图片描述

    切换后效果如下:
    在这里插入图片描述

    小结

    这节总结了“IDEA 强大的文件对比功能”,希望能对大家有所帮助,请各位小伙伴帮忙 【点赞】+【收藏】+ 【评论区打卡】, 如果有兴趣跟小明哥一起学习Java的,【关注一波】不迷路哦。

    请到文章下方帮忙【一键三连】谢谢哈!

    在这里插入图片描述

    导航

    ✪ IDEA从零到精通目录索引
    ◄上一篇【33】IDEA优化导包(自动导入包、删除包)
    ►下一篇【35】各种搜索功能

    热门专栏推荐

    【1】Java小游戏(俄罗斯方块、植物大战僵尸等)
    【2】JavaWeb项目实战(图书管理、宿舍管理等)
    【3】JavaScript精彩实例(飞机大战、验证码等)
    【4】Java小白入门200例
    【5】从零学Java、趣学Java
    【6】IDEA从零到精通
    在这里插入图片描述

    展开全文
  • 摘要:C#源码,文件操作,文件比较 文件比较,C#实例源代码,一个小小的文件操作实例,文件比较程序的一个典型实例。
  • ExamDiff Pro 是一款优秀的可视化电脑文件对比工具和目录比较合并工具,能帮助用户快速比对文件内容、文件夹、Office文档(Word、Excel和PDF文档)、zip压缩文档以及远程计算机上面等多种文件的差异之处,并用不同的...
  • 文件对比软件

    2019-02-21 08:37:49
    文件对比软件,可以进行不同文件的差异比较
  • 主要介绍了ios实现文件对比的方法,主要是用到了filemanager,有需要的小伙伴可以参考下。
  • 文件比较工具

    2018-11-20 10:39:06
    文件比较工具,能比较各种格式的文件,能够快速的找到两个文件不相同的地方。
  • 文件对比工具

    2015-04-30 11:00:04
    此文件是文件对比工具绿色版本,可以对比文件内容的不同
  • 比较的数据换行,可以列出文件中的异同之处的数据,
  • 文件加密 文件比较 文件/文件夹损毁实用工具。文件编码后可用同一密钥进行解码恢复
  • WinCMD文件对比工具

    2018-07-19 21:56:35
    文件对比,支持对比目录分级形式,分支下文件差异对比,相互同步
  • java实现文件对比

    2022-07-08 18:19:04
    基于java实现类似于svn的文件对比功能及效果,该对比适用于html,js,css,text等

    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();"><i
                      class="fa fa-search"></i>&nbsp;搜索</a>
                  <a class="btn btn-warning btn-rounded btn-sm" onclick="reset1();"><i
                      class="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_0
        String 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_0
        String 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,返回result
            for (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);
                //插入到result
                insert(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;
        }
    
        //将源文件中没变的内容插入result
        public 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,默认值为true
                drawFileList: true,
                //允许切换文件摘要列表:true或false,默认值为true
                fileListToggle: false,
                //选择文件摘要列表是否开始可见:true或false,默认值为false
                fileListStartVisible: false,
                //允许切换每个文件内容:true或false,默认值为true
                fileContentToggle: false,
                //匹配level: 'lines'用于匹配行, 'words' 用于匹配行和单词,或者设置为'none',默认为none
                matching: '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\costemp
        private 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

    展开全文
  • Mac好用的文件对比工具Beyond Compare 4

    千次阅读 2021-12-21 10:26:06
    Beyond Compare for Mac(文件比较对比工具)允许您快速,轻松地比较您的文件和文件夹。通过使用简单,强大的命令,您可以专注于您感兴趣的差异,忽略其余的。然后,您可以合并更改,同步文件。您可以高速比较整个驱动...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,940,118
精华内容 1,576,047
关键字:

文件对比