EXCEL POI 合并单元格解析

excel超级解析之Poi-SAX解析工具 Excel文件导入的时候有大量的数据需要解析时用传统的方式解析读取行数据会很缓慢,特别是xlsx格式的excel文件可能有上百万行的数据量。 Poi的Sax解析是把xlsx格式的excel文件先解析成xml,再直接从内存读取xml数据处理,这样的速度会很快。 一、区分xls和xlsx的文件并执行相应的方法 /** * excel文件解析 * @param attachFileInfo 定义的附件实体类 * @return * @throws Except. 阅读详情

EXCEL POI 合并单元格解析

1、EXCEL2007的合并单元格的XML格式

<mergeCells count="2">
		<mergeCell ref="A1:A2"/>
		<mergeCell ref="B3:B4"/>
</mergeCells>

mergeCells 里面包含了所有合并单元格的情况,需要读取到mergeCell就可以知道 该Sheet的所有单元格的合并情况

2 、SAX解析实现

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


/**
 * 类名称:CellMergeParser
 * 类描述:
 */
public class CellMergeParser {
    private XSSFReader xssfReader;

    List<String> merges = new ArrayList<>();
    InputStream is;

    /**
     * 构造方法
     */
    public CellMergeParser(String filename) throws Exception {
        if (StringUtils.isEmpty(filename))
            throw new Exception("文件名不能空");
        is = new FileInputStream(new File(filename));
        OPCPackage pkg = OPCPackage.open(is);
        init(pkg);

    }

    public CellMergeParser(InputStream is) throws Exception {
        if (null == is)
            throw new Exception("流不能空");
        OPCPackage pkg = OPCPackage.open(is);
        init(pkg);
    }

    private void init(OPCPackage pkg) throws IOException, OpenXML4JException {
        xssfReader = new XSSFReader(pkg);
    }

    /**
     * 获取sheet
     *
     * @throws Exception
     */
    public List<String> process(int sheetIndex) throws Exception {
        SharedStringsTable sst = null;
        try {
            sst = xssfReader.getSharedStringsTable();
            XMLReader parser = fetchSheetParser(sst);
            Iterator<InputStream> it = xssfReader.getSheetsData();
            int index = 0;
            while (it.hasNext()) {
                index++;
                if (index == sheetIndex) {
                    InputStream sheet = it.next();
                    InputSource sheetSource = new InputSource(sheet);
                    parser.parse(sheetSource);
                    sheet.close();


                    return merges;
                }
            }
            throw new IllegalArgumentException("sheet index not exist");
        } finally {
            try {
                is.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

    }

    /**
     * 加载sax 解析器
     *
     * @param sst
     * @return
     * @throws SAXException
     */
    private XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException {
        XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
        ContentHandler handler = new PagingHandler(sst);
        parser.setContentHandler(handler);
        return parser;
    }

    /**
     * See org.xml.sax.helpers.DefaultHandler javadocs
     */
    private class PagingHandler extends DefaultHandler {
        private SharedStringsTable sst;

        private PagingHandler(SharedStringsTable sst) {
            this.sst = sst;
        }

        /**
         * 开始元素
         */
        @Override
        public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
            //获取所有的 cell
            if ("mergeCell".equalsIgnoreCase(name)) {
                String value = attributes.getValue("ref");
                merges.add(value);
            }
        }

        /**
         * 获取value
         */
        @Override
        public void endElement(String uri, String localName, String name) throws SAXException {
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
        }

    }

    /**
     * 转换成 merge bean
     *
     * @return
     */
    public List<MergeBean> convertBean() {
        List<MergeBean> mergeBeans = new ArrayList<>();

        merges.forEach(v -> {
            MergeBean mergeBean = RowColUtil.calcMerge(v);
            mergeBeans.add(mergeBean);

        });

        return mergeBeans;
    }

}

通过对EXCEL的格式理解,使用XML的SAX解析方案 解析出所有的CELLMerge元素,然后转化为下标范围

import org.apache.poi.ss.util.CellReference;

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A1:A2
 *
 * @author dean <tanping>
 * @version 1.0.0
 * @date 2020/01/08 17:10
 * @since 1.0.0
 */
public class RowColUtil {
    /**
     * 正则匹配 mergeBean
     * @param group
     * @return
     */
    public  static  MergeBean calcMerge(String group){
        group = group.toLowerCase();
        String[] rw = group.split(":");

        Pattern p = Pattern.compile("[a-z]+|\\d+");
        Matcher m = p.matcher(rw[0]);
        ArrayList<String> start = new ArrayList<>();
        while (m.find()) {
            start.add(m.group());
        }

        m = p.matcher(rw[1]);
        ArrayList<String> end = new ArrayList<>();
        while (m.find()) {
            end.add(m.group());
        }

        int firstCol = CellReference.convertColStringToIndex(start.get(0));
        int firstRow = Integer.parseInt(start.get(1));

        int endCol = CellReference.convertColStringToIndex(end.get(0));
        int endRow = Integer.parseInt(end.get(1));

        MergeBean mergeBean = new MergeBean();
        mergeBean.setFirstColumn(firstCol);
        mergeBean.setFirstRow(firstRow);
        mergeBean.setLastColumn(endCol);
        mergeBean.setLastRow(endRow);

        return mergeBean;
    }
}

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

/**
 * Merge group组
 * [A1:A2, B3:B4]
 *  row 从1 开始
 * @author dean <tanping>
 * @version 1.0.0
 * @date 2020/01/08 17:06
 * @since 1.0.0
 */
@Getter
@Setter
@ToString
public class MergeBean {
    int firstRow;
    int firstColumn;
    int lastRow;
    int lastColumn;

    /**
     * 是否包含
     * @param row
     * @param column
     * @return
     */
    public boolean isMergeGroup(int row,int column){
        if (row >= firstRow && row <= lastRow) {
            if (column >= firstColumn && column <= lastColumn) {
                return true;
            }
        }
        return false;
    }

    /**
     * 生成唯一值
     * @return
     */
    public String createdKey(){
        return firstColumn+"-"+firstRow;
    }
}

import lombok.Getter;
import lombok.Setter;
import org.apache.poi.ss.util.CellReference;

import javax.ws.rs.GET;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 分组缓存
 *
 * @author dean <tanping>
 * @version 1.0.0
 * @date 2020/01/08 17:22
 * @since 1.0.0
 */
@Getter
@Setter
public class MergeDataCacheManage {

    /**
     * 默认后缀
     */
    public static final String POSTFIX = "_MG";

    private List<MergeBean> mergeBeans;
    private ConcurrentHashMap<String, String> groups = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String, String> values = new ConcurrentHashMap<>();

    private int mergeMax = 0;
    private String postfix;

    /**
     * 创建merge cache
     *
     * @param mergeBeans
     */
    public MergeDataCacheManage(List<MergeBean> mergeBeans) {

        this.mergeBeans = mergeBeans;
        if (mergeBeans != null) {
            mergeBeans.forEach(mb -> {
                if (mb.getLastColumn() >= mergeMax) {
                    mergeMax = mb.getLastColumn();
                }
            });
        }
        postfix = POSTFIX;
    }


    /**
     * row 从第1开始
     * col 从0 开始
     * @param data
     * @param row
     */
    public synchronized  HashMap<String, String> caclGroup(HashMap<Integer, String> data, int row) {
        if (mergeMax == 0) {
            return null;
        }
        HashMap<String, String> postFixMap = null;
        for (int i = 0; i <= mergeMax; i++) {
            MergeBean mb = existGroup(row, i);
            if (mb != null) {
                if (postFixMap == null) {
                    postFixMap = new HashMap<>();
                }
                caclPostFix(postFixMap,data,mb,row,i);
            }
        }
        return postFixMap;
    }


    /**
     * 分组 + 赋值
     * @param postFixMap
     * @param data
     * @param mb
     * @param row
     * @param col
     */
    public synchronized void caclPostFix(HashMap<String, String> postFixMap, HashMap<Integer, String> data, MergeBean mb, int row, int col) {
        String key = mb.createdKey();
        if (groups.get(key) == null) {
            groups.put(key, UUID.random());
            if (data.get(col)!=null) {
                values.put(key, data.get(col));
            }
        }
        data.put(col,values.get(key));

        String colName = CellReference.convertNumToColString(col);
        postFixMap.put(colName+postfix,groups.get(key));
    }


    /**
     * 是否存在组
     *
     * @param row
     * @param col
     * @return
     */
    public MergeBean existGroup(int row, int col) {

        for (MergeBean mb : mergeBeans) {
            if (mb.isMergeGroup(row, col)) {
                return mb;
            }
        }
        return null;
    }

}

对解析出来的结果进行计算。

测试

import java.util.List;

/**
 * TODO
 *
 * @author dean <tanping>
 * @version 1.0.0
 * @date 2020/01/08 10:14
 * @since 1.0.0
 */
public class SaxTest {

    public static void main(String[] args) throws Exception {
        String filepath = "C:\\Users\\tanping.GLOBALE\\Desktop\\demo.xlsx";
        CellMergeParser reader = new CellMergeParser(filepath);
        List<String> result = reader.process(1);

        System.out.println(result);

        result.forEach(v->{
            MergeBean mergeBean = RowColUtil.calcMerge(v);
            System.out.println(mergeBean);
        });
    }
}

【Java】POI 解析有合并单元格的 Excel POI 解析有合并单元格的 Excel 阅读详情

相关推荐

SpringBoot + EasyExcel + POI 实战:解析复杂Excel(含合并单元格与内嵌图片)的完整方案

本文详细介绍了如何使用SpringBoot结合EasyExcel和POI处理复杂Excel文件,包括合并单元格和内嵌图片的解析。通过技术选型、环境搭建、核心代码实现和性能优化实践,提供了一套完整的解决方案,帮助开发者高效处理Excel数据导入问题。

weixin_33712987的博客 400

easypoi导出时合并单元格

java使用easypoi导出时进行单元格合并

wscn9527的博客 3292

Apache POI 解析复杂的excel表格

一篇文章教你如何使用apache POI框架解析工作中遇到的复杂的Excel文件,内含完整项目代码以及测试文件。

余鱼瑜渔的博客 3925

java poi excel合并单元格 相同的列以及在有父级约束条件下合并二级列

java poi excel合并单元格 相同的列以及在有父级约束条件下合并二级列

小小芽儿 1043

easyuiPoi导出Excel工具类封装(支持合并单元格)

easyuiPoi 通过模板导出Excel、支持纵向合并单元格(合并重复内容)。压缩包包含公共工具类、示例模板、调用截图。

Spring AI + RAG 构建电商智能客服:从 PDF 文档解析到精准问答的全链路实战

核心框架:向量数据库:- PostgreSQL + pgvector (生产推荐)- Redis Stack (轻量级方案)- ChromaDB (快速原型)文档解析:- Apache PDFBox: PDF 文本提取- Spring AI Document Readers: 结构化解析大模型:- 阿里云百炼 (DashScope)- 本地部署:Qwen/ChatGLM/*** 电商领域实体*/@Data@Builder@ToString/*** 商品类型。

一起修行,不孤单。这里有编程语言、开发工具、学习方法论和踩坑笔记。用简单的话说复杂的事,陪你从小白到进阶。周更干货,欢迎一起成长! 379

SAX事件驱动方式解析大数据量Excel文件(亲测3万行Excel数据无压力读取)

最近在做项目功能时,发现传统`Apache POI`提供的API去解析大量数据Excel文件时,很容易抛出内存溢出的异常,导致Excel数据很难读到内存上去。因此在网上找了很多资料,最后找到了`SAX事件驱动`方式解析Excel文件,完美解决了大数据量读取问题,在这里简单做下整理分享给大家!

laizhenghua的博客 6771

Linux中断子系统分析之(四):驱动程序申请中断

中断子系统中有一个重要的设计机制,那就是Top-half和Bottom-half,将紧急的工作放置在Top-half中来处理,而将耗时的工作放置在Bottom-half中来处理。 如果中断不分上下半部处理,那么意味着只有等上一个中断完成处理后才会打开中断,下一个中断才能得到响应。当某个中断处理处理时间较长时,很有可能就会造成其他中断丢失而无法响应,影响系统性能。 中断分成上下半部处理可以提高中断的响应能力,在上半部处理完成后便将中断打开,这样就可以响应其他中断了,等到中断退出的时候再进行下半部的处理。为了进

m0_46525308的博客 1225

POI解析excel文件读取文件(含合并单元格)

poi-----解析excel文件----解决合并单元格无法读取内容

lxd1373006963的博客 1653

面向多目标跟踪的数据关联方法研究综述

摘要:多目标跟踪技术在军事和民用领域具有广泛应用,其核心挑战在于数据关联问题。本文系统梳理了数据关联的主要解决方法,首次将经典算法分为确定性关联和概率性关联两大类。确定性关联(如NNDA、GNN、MHT)采用"硬分配"策略,计算效率高但易受噪声干扰;概率性关联(如PDA、JPDA、PMHT)通过"软分配"处理不确定性,更适合复杂场景。文章详细分析了各类算法的原理、适用条件和优缺点,并探讨了智能学习等新兴技术在视觉跟踪等领域的应用。研究指出,尽管随机集滤波等新方法出现,

qq_43416206的博客 1139

ESXi 6.7升级17700523补丁全流程:从下载到验证的保姆级教程

本文提供ESXi 6.7升级17700523补丁的完整流程指南,涵盖从下载、上传到验证的详细步骤。通过SSH命令和vSphere Client操作,确保系统管理员能够安全高效地完成补丁升级,提升虚拟化环境的安全性和稳定性。

linux6sysadmin的博客 839

【Apache POI】Java解析Excel文件并处理合并单元格-粘贴即用

同为牛马,点个赞吧!一、Excel文件样例二、工具类源码登录后复制 import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.XSSF...

weixin_40639767的博客 243

ClickHouse的bitmap使用

ClickHouse的bitmap使用 bitmap的基本使用 在CK中bitmap有两种构建方式,在ClickHouse的官网有说明: (1)一个是由聚合函数groupBitmapState构造的, (2)另一个是由Array Object构造的。同时还可以将位图对象转化为数组对象。 bitmap实战 数据和基本数据表准备 创建一张基本表,一个用户表,有多个描述的维度,每个维度由该维度的唯一id。 CREATE TABLE test02(id UInt16, tag1 UInt8, tag2 UInt8,

zg_hover的专栏 5653

java poi解析excel,带合并单元的excel

首先,mavn导入jar包                        org.apache.poi             poi             3.11                               org.apache.poi             poi-ooxml             3.11

shang的博客 5130

Pinocchio 安装教程|机器人学的必备库

安装pinocchio,不要安装pip3 install pinocchio!

darcsdn 1660

芒果YOLOv12改进90:检测头篇之ShareSepHead:即插即用|原创新颖共享Sep检测头,更省参数量,更高效,打造新型YOLOv8检测器,精度高效涨点

芒果YOLOv12改进90:检测头篇之ShareSepHead:即插即用|原创新颖共享Sep检测头,更省参数量,更高效,打造新型YOLOv8检测器,精度高效涨点

包括YOLOv5、YOLOv7、YOLOv8等模型改进 343

POI导入数据解决多表头,合并单元格数据读取问题

poi导入数据解决多表头,合并单元格数据读取问题

weixin_47064169的博客 6012

震惊!用刚发布的GPT-5写研究现状,文献综述写作一整个大逆袭(附步骤+10条AI提示词)

每类分别给出:国内重点(3 条)、国外重点(3 条)、代表性方法(2–3 条)、代表成果(各 1–2 条)、主要问题(2 条)。每个场景给出:技术方案(2–3 种)、研究目标、实际成效/案例、当前挑战(3 点)。指令:基于国内外现状,系统列出当前学界的研究空白、关键未解问题与争议焦点(每项配简要证据/示例),并针对每个空白提出 1–2 条可行的研究方向或方法路径。三、差异与研究空白分析(≥300 字)。对每个小节提供:小标题、中心论点(1 句)、拟写要点(3–5 条)、建议引用类型(理论/方法/案例)。

qq_64378896的博客 114

java 判断excel是不是合并单元_java 解析excel,带合并单元的excel

标签:首先,mavn导入jar包org.apache.poipoi3.11org.apache.poipoi-ooxml3.11org.apache.poipoi-ooxml-schemas3.11staxstax-api1.0.1org.apache.xmlbeansxmlbeans2.6.0其次,代码如下:package excel;import java.io.File;import jav...

weixin_31969199的博客 680

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Java使用Apache.POI导入包含合并单元格的Excel文档

1、导入的excel表格 2、Demo展示:导入包含合并单元格的Excel文档的代码如下所示。 package cn.test; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import ...

qq_36276633的博客 1414

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

poiexcel 读取引用列_Java POI读取Excel的时候怎么按列读取-问答-阿里云开发者社区-阿里云...

import java.io.File;import java.io.FileInputStream;import java.io.InputStream;import java.util.HashMap;import java.util.Map;import java.util.Map.Entry;import java.util.Random;import org.apache.poi.ss....

weixin_42405705的博客 385

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

【Java】Apache POI 解析带有合并单元格的Excel

树状结构表格读取,按每一行获取其信息。

bboyOA的博客 213

POI读取excel合并单元格内容

import java.io.File; import java.io.IOException; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; im...

qq_23292875的博客 5843

Apache POI解析 ~ 行合并的单元格

使用Apache POI解析一个如下图样式的excel文件 Apache POI 针对Workbook有两种不同实现方式,分别是HSSFWorkbook(解析.xls文件)和XSSFWorkbook(解析.xlsx文件) 1.添加Maven依赖 <dependencies> <dependency> <groupId>org.apache.poi</groupId> &l.

houkai的博客 1179

POI-获取Excel中合并单元格问题

项目需要读取上传的excel中的合并单元格。于是找到POI包: 主要是poi-x.x.jar 和 poi-ooxml-x.x.jar包 首先是判断当前sheet页是否存在合并单元格,使用getNumMergedRegions()获取当前sheet页中的合并单元格总数. 如下表总共有8行3列【行:0-7;列:0-2】;其中共有合并单元格A、B、E、F、G、H 6个; int

_0xD00C 5754
上一篇: fastDfS文件系统配置
下一篇: python 服务文件夹自动同步备份脚本
doubleping
博客等级 码龄17年 23粉丝 45原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值