当前位置: 首页 > 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;且受限于禁止商业发…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

微服务商城-商品微服务

数据表 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 商…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

LRU 缓存机制详解与实现(Java版) + 力扣解决

&#x1f4cc; LRU 缓存机制详解与实现&#xff08;Java版&#xff09; 一、&#x1f4d6; 问题背景 在日常开发中&#xff0c;我们经常会使用 缓存&#xff08;Cache&#xff09; 来提升性能。但由于内存有限&#xff0c;缓存不可能无限增长&#xff0c;于是需要策略决定&am…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing

Muffin 论文 现有方法 CRADLE 和 LEMON&#xff0c;依赖模型推理阶段输出进行差分测试&#xff0c;但在训练阶段是不可行的&#xff0c;因为训练阶段直到最后才有固定输出&#xff0c;中间过程是不断变化的。API 库覆盖低&#xff0c;因为各个 API 都是在各种具体场景下使用。…...