Java比较两个Excel是否内容一致

领导每天让比较两个Excel中的内容,为了节省工作效率多摸鱼,就写了个java接口,通过上传两个文件 进行代码比较得到详细的比较结果(这个需要自己根据日志二开) 目前只实现了比较功能

话不多说直接上代码,具体看注释

package com.yxy.aob.util;import cn.hutool.core.collection.CollUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;/*** @Description: excel对比* @Author: Hyz* @Date: 2024/10/14 11:33* @Version:1.0*/
@Slf4j
public class CompareTwoExcels {private final static String MSG_PREFIX = "【source】与【target】中";/*** 文件1流*/private InputStream sourceExcelFile;/*** 文件2流*/private InputStream targetExcelFile;/*** 是否模糊   true为精准匹配  false为模糊匹配*/private boolean isPerfectMatch;/*** 差集*/private List<String> differential;/*** 错误行*/private List<String> errorMsg;/*** 匹配行*/private List<String> successMsg;/*** 构造方法** @param sourceExcelFile 文件1* @param targetExcelFile 文件2* @param isPerfectMatch  表示是否需要完全匹配*/public CompareTwoExcels(InputStream sourceExcelFile, InputStream targetExcelFile, boolean isPerfectMatch) {this.sourceExcelFile = sourceExcelFile;this.targetExcelFile = targetExcelFile;this.isPerfectMatch = isPerfectMatch;this.differential = new ArrayList<>();this.errorMsg = new ArrayList<>();this.successMsg = new ArrayList<>();}public static void main(String[] args) throws IOException {try (InputStream sourceInputStream = Files.newInputStream(Paths.get("C:\\Users\\Administrator\\Desktop\\1.xlsx"));InputStream targetInputStream = Files.newInputStream(Paths.get("C:\\Users\\Administrator\\Desktop\\1 - 副本.xlsx"))) {// 初始化识别器CompareTwoExcels compareTwoExcels = new CompareTwoExcels(sourceInputStream, targetInputStream, false);// 执行识别方法 需要指定对应的sheet页 下标0开始boolean result = compareTwoExcels.comparedExcels(0, 0);log.info("result为:" + result);} catch (Exception e) {e.printStackTrace();}}/*** 获取初始化文件的sheet数量** @param type 1 表示sourceExcelFile 2 表示targetExcelFile*/private int getSheetNum(Integer type) {log.info("sourceExcelSheetNum为:" + this.sourceExcelFile);try (Workbook workbook = WorkbookFactory.create(type == 1 ? this.sourceExcelFile : this.targetExcelFile)) {return workbook.getNumberOfSheets();} catch (IOException e) {return 0;}}/*** 比较两个excel** @param sourceExcelSheetNum sheet  从0开始* @param targetExcelSheetNum sheet  从0开始*/private boolean comparedExcels(int sourceExcelSheetNum, int targetExcelSheetNum) {log.info("------------------------读取Excel1数据------------------------");List<List<String>> sourceList = this.readExcel(sourceExcelSheetNum, this.sourceExcelFile, "source");log.info("------------------------读取Excel2数据------------------------");List<List<String>> targetList = this.readExcel(targetExcelSheetNum, this.targetExcelFile, "target");if (CollUtil.isEmpty(sourceList) || CollUtil.isEmpty(targetList)) {log.error("sourceList为空!!!");return false;}// 行数不一致直接返回falseif (sourceList.size() != targetList.size()) {log.error("sourceList与targetList长度不一致");return false;}log.info("------------------------开始匹配:【{}】------------------------", isPerfectMatch ? "精准匹配" : "模糊匹配");boolean result = true;try {// 模糊匹配和精准匹配区分if (!isPerfectMatch) {// 模糊匹配 即两份excel的每一行不定for (int i = 1; i <= sourceList.size(); i++) {log.info("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 第【{}】行 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓", i);// 表格1的第i行List<String> list1 = sourceList.get(i - 1);List<String> list2 = targetList.get(i - 1);// 判断1、两个表格的同一行是否相同 (即表格1的第1行和表格2的第1行hashCode是否一致)if (list1.hashCode() != list2.hashCode()) {log.info("------{}第【{}】行匹配结果------UNKNOWN", MSG_PREFIX, i);// 判断2、 需要比较表格1的这一行在表格二中是否存在if (targetList.contains(list1)) {int i1 = targetList.indexOf(list1);log.info("---------详情:【source】中第【{}】行与【target】中第【{}】行匹配(跨行)", i, i1 + 1);this.successMsg.add("【source】中第【" + i + "】行与【target】中第【" + (i1 + 1) + "】行匹配(跨行)");//                            List<String> cells = targetList.get(targetList.indexOf(list1));
//                            for (int j = 1; j <= list1.size(); j++) {
//                                if (cells.contains(list1.get(j - 1))) {
//                                    log.info("---------详情:第【{}】行,第【{}】列 匹配", i, j);
//                                    this.successMsg.add(MSG_PREFIX + "第【" + i + "】行,第【" + j + "】列 匹配");
//                                } else {
//                                    log.info("---------详情:第【{}】行,第【{}】列 不匹配", i, j);
//                                    this.errorMsg.add(MSG_PREFIX + "第【" + i + "】行,第【" + j + "】列 不匹配");
//                                    result = false;
//                                }
//                            }} else {log.info("---------详情:【source】中第【{}】行在【target】中不存在", i);this.errorMsg.add(MSG_PREFIX + "第【" + i + "】行均不存在");result = false;}} else {log.info("------{}第【{}】行匹配结果------SUCCESS", MSG_PREFIX, i);this.successMsg.add(MSG_PREFIX + "第【" + i + "】行匹配");}}} else {// 精准匹配 即两份excel的每一行每一列格式相同for (int i = 1; i <= sourceList.size(); i++) {// 表格1的第i行List<String> list1 = sourceList.get(i - 1);// 表格2的第i行List<String> list2 = targetList.get(i - 1);// 精准匹配 即两份excel的每一行每一列都完全匹配// list2.equals(list1)或list1.hashCode() == list2.hashCode()if (list1.hashCode() == list2.hashCode()) {log.info("------第【{}】行, 匹配------", i);this.successMsg.add(MSG_PREFIX + "第【" + i + "】行, 匹配");} else {log.info("------第【{}】行, 不匹配------", i);this.errorMsg.add(MSG_PREFIX + "第【" + i + "】行, 不匹配");result = false;}}}} catch (IndexOutOfBoundsException ex) {log.error("两个表格可能存在行数不一致,导致sourceList与targetList长度不一致!");result = false;} finally {log.info("------------------------比较结束------------------------");}return result;}/*** 读取excel 封装成集合* 该程序需要传入一份excel 和excel的列数 行数由程序自动检测* 注意:该方法统计的行数是默认第一行为title 不纳入统计的** @return excel的集合*/private List<List<String>> readExcel(int sheetNum, InputStream inputStream, String type) {List<List<String>> list = new ArrayList<>();// 建需要读取的excel文件写入streamtry (Workbook workbook = WorkbookFactory.create(inputStream)) {// 指向sheet下标为0的sheet 即第一个sheet 也可以按在sheet的名称来寻找Sheet sheet = workbook.getSheetAt(sheetNum);// 获取sheet1中的总行数int rowTotalCount = sheet.getLastRowNum();//获取总列数int columnCount = 0;for (int i = 0; i <= rowTotalCount; i++) {// 获取第i列的row对象Row row = sheet.getRow(i);ArrayList<String> listRow = new ArrayList<>();int physicalNumberOfCells = row.getPhysicalNumberOfCells();if (physicalNumberOfCells >= columnCount) {columnCount = physicalNumberOfCells;}for (int j = 0; j < physicalNumberOfCells; j++) {//下列步骤为判断cell读取到的数据是否为null 如果不做处理 程序会报错String cell = null;//如果未null则加上""组装成非null的字符串if (row.getCell(j) == null) {cell = row.getCell(j) + "";listRow.add(cell);//如果读取到额cell不为null 则直接加入	listRow集合} else {cell = row.getCell(j).toString();listRow.add(cell);}}list.add(listRow);}log.info("Excel【{}】中【{}】页签共计:{}行,{}列(列为最大列)", type, sheet.getSheetName(), rowTotalCount + 1, columnCount);} catch (IOException e) {log.error("读取excel sheet{}失败: {}", sheetNum, e.getMessage());}return list;}/*** ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓私有属性方法↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/public List<String> getDifferential() {return differential;}private void setDifferential(List<String> differential) {this.differential = differential;}public List<String> getErrorMsg() {return errorMsg;}private void setErrorMsg(List<String> errorMsg) {this.errorMsg = errorMsg;}public List<String> getSuccessMsg() {return successMsg;}private void setSuccessMsg(List<String> successMsg) {this.successMsg = successMsg;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/881768.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ORM框架简介

什么是ORM&#xff1f; ORM&#xff08;Object-Relational Mapping&#xff0c;对象关系映射&#xff09;是一种编程技术&#xff0c;用于在关系数据库和对象程序语言之间转换数据。ORM框架允许开发者以面向对象的方式来操作数据库&#xff0c;而不需要编写复杂的SQL语句。简单…

【Linux】命令行下的增删查改之“查看”

致谢:Linux常用命令大全(手册) – 真正好用的Linux命令在线查询网站 提供的命令查询 头部内容获取(head) head命令的功能是显示文件开头的内容&#xff0c;默认值为前10行。 指令参数&#xff1a; -n 定义显示行数 -c 指定显示头部内容的字符数 -v 总是显示文件名的头信…

告别手动计数:智能统计模型用量,释放设计潜力

添加HanTop-MKT&#xff0c;免费获取统计零件数量模型 非标设备行业的设计BOM因为涉及物料采购与装配数量要求&#xff0c;往往面临着需要数据准确性的严格要求&#xff0c;在缺乏自动化工具情况下&#xff0c;手动统计零件用量变得更加困难&#xff0c;且数据准确性得不到保障…

【uniapp】设置公共样式,实现公共背景等

目录 1、 全局渐变背景色 2.1 创建common目录 2.2 在common下新建style和images等目录 2.3 在style下新建common-style.scss 2.4 common-style输入全局渐变颜色 2.5 引入样式 2.6 业务页面引入 2.7 展示 2、全局字体颜色 2.1 新建base-style.scss文件 2.2 设置base-…

07 django管理系统 - 部门管理 - 搜索部门

在dept_list.html中&#xff0c;添加搜索框 <div class"container-fluid"><div style"margin-bottom: 10px" class"clearfix"><div class"panel panel-default"><!-- Default panel contents --><div clas…

Redis 其他类型 渐进式遍历

我们之前已经学过了Redis最常用的五个类型了&#xff0c;然而Redis还有一些在特定场景下比较好用的类型 Redis最关键的五个数据类型&#xff1a; 上面的类型是非常常用&#xff0c;很重要的类型。 除此之外的其他类型不常用&#xff0c;只是在特定的场景能够发挥用处&#…

无极低码课程【java(jdk)windows下安装及环境变量配置】

在Windows环境中安装JDK 7教程 Java Development Kit (JDK) 是开发Java应用程序所必需的工具包。本教程将指导您在Windows操作系统上安装JDK 7。 准备工作 下载JDK 7安装包 访问 Oracle官方网站 下载JDK 8的安装包。选择适合您操作系统的安装包(例如 jdk-7u80-windows-x64.ex…

vmware虚拟机 报错:客户机操作系统已禁用 CPU,请关闭或重置虚拟机 的解决方法

打开cpu虚拟化全部进行勾选 ctrl e 进行关机 勾选上打开就好了 如果没有那个选项 关机>打开虚拟机>管理>更改硬件兼容性> 往小处改改> >更改此虚拟机

[LeetCode] 515. 在每个树行中找最大值

题目描述&#xff1a; 给定一棵二叉树的根节点 root &#xff0c;请找出该二叉树中每一层的最大值。 示例1&#xff1a; 输入: root [1,3,2,5,3,null,9] 输出: [1,3,9]示例2&#xff1a; 输入: root [1,2,3] 输出: [1,3]提示&#xff1a; 二叉树的节点个数的范围是 [0,10…

基于SpringBoot的个性化健康建议平台

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理基于智能推荐的卫生健康系统的相关信息成为…

OpenTrans

比较的方法Cat-Seg不好复现

Spring 实现 3 种异步流式接口,干掉接口超时烦恼

大家好&#xff0c;我是小富&#xff5e; 如何处理比较耗时的接口&#xff1f; 这题我熟&#xff0c;直接上异步接口&#xff0c;使用 Callable、WebAsyncTask 和 DeferredResult、CompletableFuture等均可实现。 但这些方法有局限性&#xff0c;处理结果仅返回单个值。在某…

幸运7游戏模拟 python

题目&#xff1a; 幸运"7"游戏,用计算机模拟掷骰子的过程&#xff0c;测算两个骰子点数之和为7的概率。 游戏规则是你丢两个骰子&#xff0c;如果其点数之和为7你就赢4元&#xff0c;不是7你就输1元。 假设你刚开始有10元&#xff0c;当全部输掉为0元的时候游戏结…

【网络安全】1,600$:Auth0 错误配置

未经许可,不得转载。 文章目录 前言正文漏洞案例修复建议前言 Auth0 是一个广泛用于网站和应用程序的身份验证平台,负责管理用户身份并确保其服务的安全访问。该平台提供了多种工作流程,以无缝集成登录和注册流程。 在 Auth0 中创建新应用时,注册选项默认启用。当系统禁用…

Android 无Bug版 多语言设计方案!

出海业务为什么要做多语言&#xff1f; 1.市场扩大与本地化需求&#xff1a; 通过支持多种语言&#xff0c;出海项目可以触及更广泛的国际用户群体&#xff0c;进而扩大其市场份额。 本地化是吸引国际用户的重要策略之一&#xff0c;而语言本地化是其中的核心。使用用户的母语…

c语言字符函数

1&#xff0c;字符分类函数&#xff1a; 例如&#xff1a;写一个代码将字符串中的小写字母转化成大写字母 就可以用到上述islower函数判断字符是否是小写 2.字符转换函数 c语言提供了两个字符转换函数 1.int tolower (int c); //将输入进去的大写字母转化成小写 2,int …

IRP默认最小流程

IRP是Windows内核中的一种非常重要的数据结构。上层应用程序与底层驱动程序通信时&#xff0c;应用程序会发出I/O请求&#xff0c;操作系统将相应的I/O请求转换成相应的IRP&#xff0c;不同的IRP会根据类型被分派到不同的派遣例程中进行处理。 irp相当于R3下的消息&#xff0c…

rtsp协议:rtsp协议参数介绍

目的&#xff1a; 实时流协议&#xff08;RTSP&#xff09;用于建立和控制单个或多个时间同步的连续媒体流&#xff0c;例如音频和视频。RTSP 通常不负责实际传输这些连续的媒体流&#xff0c;但可以将连续媒体流与控制流进行交错传输&#xff08;参见第 10.12 节&#xff09;。…

学习Redisson实现分布式锁

官网&#xff1a;https://redisson.org/ 官方文档&#xff1a;https://redisson.org/docs/getting-started/ 官方中文文档&#xff1a;https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95 1、引入依赖 <!--redisson--> <dependency><groupId>or…

金融大数据平台总体技术

目录 金融大数据平台应用场景风险管理 场景描述解决方案​​​​​​​市场营销 ​​​​​​​场景描述解决方案​​​​​​​金融大数据信息价值链​​​​​​​金融大数据平台总体目标金融大数据平台功能技术要求​​​​​​​ ​​​​​​​概述数据接入功能要求 ​​…