当前位置: 首页 > news >正文

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;}
}

相关文章:

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

领导每天让比较两个Excel中的内容&#xff0c;为了节省工作效率多摸鱼&#xff0c;就写了个java接口&#xff0c;通过上传两个文件 进行代码比较得到详细的比较结果(这个需要自己根据日志二开) 目前只实现了比较功能 话不多说直接上代码&#xff0c;具体看注释 package com.yx…...

UniApp入门教程

UniApp X 是一种用于构建跨平台应用程序的框架&#xff0c;它基于 Vue.js 并通过 UniApp 技术栈支持多种平台&#xff0c;如微信小程序、支付宝小程序、H5、Android 和 iOS。以下是 UniApp X 的一些关键特点和基础知识&#xff1a; UniApp X 的特点 跨平台支持&#xff1a; 可…...

Vue.js中使用Element UI实现动态表单项管理及验证

在Vue.js项目中&#xff0c;表单是与用户交互的重要部分&#xff0c;特别是在需要动态管理表单项的场景下&#xff0c;如何优雅地实现添加、删除、上移、下移及验证功能变得尤为重要。本文将详细介绍如何使用Element UI来实现一个包含动态表单项管理以及验证功能的表单。 效果…...

一插U盘就提示格式化?原因、恢复与预防全攻略

一、现象直击&#xff1a;U盘插入电脑即提示格式化 在日常的工作与生活中&#xff0c;U盘作为重要的数据存储和传输工具&#xff0c;被广泛应用于各类场景。然而&#xff0c;有时当我们满怀期待地将U盘插入电脑时&#xff0c;却会遭遇一个令人头疼的问题——系统弹出提示框&am…...

云电脑使用教程标准版

云电脑&#xff0c;也称为云桌面&#xff0c;是一种通过互联网连接远程服务器&#xff0c;使用虚拟桌面环境来执行计算任务的技术。川翔云电脑通过创建软件镜像&#xff0c;让用户能够快速启动并使用预配置的软件和资料&#xff0c;提供高效且经济的云服务。相较于公有云服务&a…...

浏览器服务端文件下载控制(安全阻止、文件浏览器打开还是下载行为控制)

文章目录 简介Chrome已阻止不安全内容下载PDF直接打开txt、xml、js文件被自动打开了而不是下载阿里OSS设置response header阿里OSS修改metadata 简介 随着浏览器的发展&#xff0c;有很多安全方面的限制&#xff0c;对我们的文件下载行为产生了很大的影响。 在JavaScript下载…...

机器学习——量子机器学习

量子机器学习: 未来的机器学习方法 量子计算和机器学习的结合为计算科学带来了前所未有的前景。量子机器学习(QML)正在迅速发展&#xff0c;目标是利用量子计算的优势来处理传统计算机无法高效解决的问题。本文将深入探讨量子机器学习的基本概念、量子计算的关键技术、具体的量…...

[Linux] 创建可以免密登录的SFTP用户

本文主要包含: 创建新用户创建密钥对用于免密登录新用户将新建用户改造为SFTP用户为SFTP上传数据设置限速 1. 创建新用户 sudo useradd sftp_user sudo passwd sftp_user # 输入密码2. 创建密钥对 参考这篇文章 [Linux] 生成 PEM 密钥对实现服务器的免密登录 3. 将新建用户…...

【部署篇】Redis-03主从模式部署(源码方式安装)

一、准备主机 主从模式只是解决了数据备份容灾并不能解决单点故障问题&#xff0c;生产环境中需要在主从模式基础上增加哨兵&#xff0c;实现主节点宕机时自动将其中一个重节点设置为新的主节点。 主机IP角色说明192.168.128.31master&#xff0c;主节点可读写。192.168.128…...

C/C++语言基础--C++四大类型转换讲解

本专栏目的 更新C/C的基础语法&#xff0c;包括C的一些新特性 前言 通过前面几节课&#xff0c;我们学习了抽象、封装、继承、多态、异常等概念&#xff0c;这一篇我们将继续学习C的类型转换&#xff0c;和C语言还有很大区别的&#xff1b;在本节课最后&#xff0c;也简要说…...

KafKa 集群【docker compose】

文章目录 主机准备部署编辑 docker-compose.ymlcontrollerbroker生成cluster_id 一篇完整的 docker-compose.yml 文件查看集群状态使用 kafka-ui 查看拉取 kafka-ui添加集群查看集群状态 使用命令行查看 配置讲解controllerbroker 主机准备 IPcontroller idbroker id192.168.1…...

【工具篇】MLU运行XInference部署手册

文章目录 前言一、平台环境准备二、代码下载三、安装部署1.正常pip 安装 四、运行结果展示1.如果界面404或没有东西请这样做2.运行效果 前言 Xorbits Inference&#xff08;Xinference&#xff09;是一个功能强大、用途广泛的库&#xff0c;旨在为语言、语音识别和多模态模型提…...

计算机网络:数据链路层 —— 扩展共享式以太网

文章目录 共享式以太网共享式以太网存在的问题在物理层扩展以太网扩展站点与集线器之间的距离扩展共享式以太网的覆盖范围和站点数量 在链路层扩展以太网网桥的主要结构网桥的基本工作原理透明网桥自学习和转发帧生成树协议STP 共享式以太网 共享式以太网是当今局域网中广泛采…...

平安养老险深圳分公司:创新养老服务,深入践行金融为民

党的二十届三中全会《决定》提出&#xff1a;“积极发展科技金融、绿色金融、普惠金融、养老金融、数字金融&#xff0c;加强对重大战略、重点领域、薄弱环节的优质金融服务。” 为经济社会发展提供高质量服务&#xff0c;更好满足人民日益增长的美好生活需要&#xff0c;金融…...

静态站点生成器哪家强?

有一种方法&#xff0c;让你写好文档后&#xff0c;快速地让同事、用户和合作伙伴看到&#xff0c;这就是静态站点生成器。 静态站点生成器是一种软件&#xff0c;用于创建不需要服务器端脚本的网站。这些网站由纯HTML文件组成&#xff0c;可能还包括CSS和JavaScript来增强功…...

从0开始部署优化虚拟机

一&#xff0c;vm workstation 安装 CentOS-7 忽略 二、查看虚拟机IP ip address 得到 192.168.196.128/24 宿主机进行Ping测试 C:\Users\Administrator>ping 192.168.196.128正在 Ping 192.168.196.128 具有 32 字节的数据: 来自 192.168.196.128 的回复: 字节32 时间…...

录屏有道, 四款必备录屏工具推荐!

制作教程视频、游戏直播或是远程会议记录等都需要录屏&#xff0c;那么到底应该怎么录屏呢&#xff1f;接下来就给大家介绍几个好用的录屏工具 Foxit REC 直达链接&#xff1a;www.foxitsoftware.cn/REC/ 操作教程&#xff1a;立即获取 Foxit REC以其强大的功能、简洁的界面…...

5G NR:UE初始接入信令流程浅介

UE初始接入信令流程 流程说明 用户设备&#xff08;UE&#xff09;向gNB-DU发送RRCSetupRequest消息。gNB-DU 包含 RRC 消息&#xff0c;如果 UE 被接纳&#xff0c;则在 INITIAL UL RRC MESSAGE TRANSFER 消息中包括为 UE 分配的低层配置&#xff0c;并将其传输到 gNB-CU。IN…...

探索 Spring AI:Java 开发者的 AI 应用开发新利器

在当今这个由人工智能驱动的时代&#xff0c;AI 技术正在以前所未有的速度改变着我们的工作和生活方式。对于 Java 开发者来说&#xff0c;将 AI 能力集成到他们的应用程序中&#xff0c;已经成为了一个迫切的需求。阿里云开源的 Spring AI Alibaba 框架&#xff0c;正是为了满…...

Linux历史

Linux 于 1991 年由芬兰学生 Linus Torvalds 作为个人项目开始&#xff0c;旨在创建一个新的免费操作系统内核。在其历史发展中&#xff0c;Linux 内核经历了持续的增长。自 1991 年首次发布源代码以来&#xff0c;Linux 内核从少量的 C 语言文件&#xff0c;且受限于禁止商业发…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本&#xff1a; 3.8.1 语言&#xff1a; JavaScript/TypeScript、C、Java 环境&#xff1a;Window 参考&#xff1a;Java原生反射机制 您好&#xff0c;我是鹤九日&#xff01; 回顾 在上篇文章中&#xff1a;CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...

Razor编程中@Html的方法使用大全

文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

《Docker》架构

文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器&#xff0c;docker&#xff0c;镜像&#xff0c;k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...

区块链技术概述

区块链技术是一种去中心化、分布式账本技术&#xff0c;通过密码学、共识机制和智能合约等核心组件&#xff0c;实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点&#xff1a;数据存储在网络中的多个节点&#xff08;计算机&#xff09;&#xff0c;而非…...