Poi使用sax解析xlsx

本文参考了
https://blog.csdn.net/sai739295732/article/details/68489403

https://blog.csdn.net/rainyspring4540/article/details/50747122
两篇文章,感谢这两篇文章的作者

maven

<!--poi -excel表格驱动-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.10-FINAL</version>
 </dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.10-FINAL</version>
</dependency>
<!--SAX解析excel-->
<dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>2.9.1</version>
</dependency>

解析工具代码

package com.cignacmb.sms.common.util;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

public class SaxExcelUtils {
    private static List<Map<String,String>> dataListT;
    private final int startRow;
    private final int endRow;
    private int currentRow = 0;
    private final String filename;
    private static Map<String,String> map;
    static char[] strChar ;
    /**
     * 构造方法
     */
    public SaxExcelUtils(String filename,int startRow,int endRow) throws Exception{
        dataListT = new ArrayList<>();
        if(StringUtils.isEmpty(filename)) throw new Exception("文件名不能空");
        this.filename = filename;
        this.startRow = startRow;
        this.endRow = endRow+1;
        processSheet();
    }
    /**
     * 指定获取第一个sheet
     * @param filename
     * @throws Exception
     */
    private void processSheet() throws Exception {
        OPCPackage pkg = OPCPackage.open(filename);
        XSSFReader r = new XSSFReader( pkg );
        SharedStringsTable sst = r.getSharedStringsTable();
        XMLReader parser = fetchSheetParser(sst);
        Iterator<InputStream> it = r.getSheetsData();
        while(it.hasNext()){
            map = null;
            InputStream sheet1 = it.next();
            InputSource sheetSource = new InputSource(sheet1);
            parser.parse(sheetSource);
            sheet1.close();
        }
    }
    /**
     * 加载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 String lastContents;
        private boolean nextIsString;
        private String index = null;
        private PagingHandler(SharedStringsTable sst) {
            this.sst = sst;
        }
        /**
         * 开始元素 (获取key 值)
         */
        @Override
        public void startElement(String uri, String localName, String name,
                                 Attributes attributes) throws SAXException {
            if(name.equals("c")) {
                index = attributes.getValue("r");
                //判断是否是新的一行
                if(Pattern.compile("^A[0-9]+$").matcher(index).find()){
                    if(map!=null&&isAccess()&&!map.isEmpty()){
                        dataListT.add(map);
                    }
                    map = new LinkedHashMap<>();
                    currentRow++;
                }
                if(isAccess()){
                    String cellType = attributes.getValue("t");
                    if(cellType != null && cellType.equals("s")) {
                        nextIsString = true;
                    } else {
                        nextIsString = false;
                    }
                }
            }
            lastContents = "";
        }
        /**
         * 获取value
         */
        @Override
        public void endElement(String uri, String localName, String name)
                throws SAXException {
            if(isAccess()){
                if(nextIsString) {
                    int idx = Integer.parseInt(lastContents);
                    lastContents = new XSSFRichTextString(sst.getEntryAt(idx)).toString();
                    nextIsString = false;
                }
                if(name.equals("v")) {
                    map.put(index, lastContents);
                }
            }

        }
        @Override
        public void characters(char[] ch, int start, int length)
                throws SAXException {
            if(isAccess()){
                lastContents += new String(ch, start, length);
            }
        }
        @Override
        public void endDocument ()throws SAXException{
            if(map!=null&&isAccess()&&!map.isEmpty()){
                dataListT.add(map);
            }
        }

    }
    private boolean isAccess(){
        if(currentRow>=startRow&&startRow<=endRow){
            return true;
        }
        return false;
    }
    /**
     * 获取数据 并且填补字段值为空的数据
     * @return
     * @throws Exception
     */
    public List<Map<String,String>> getMyDataList() throws Exception{
        List<Map<String,String>> list = dataListT.subList(startRow, dataListT.size());
        if(!list.isEmpty()){
            Map<String,String> map = dataListT.get(0);
            List<String> com = data("A",map.size()-1);
            for(int i=0;i<list.size();i++){
                Map<String,String> returnMap = list.get(i);
                for(String str:com){
                    boolean flag = true;
                    for(Entry<String,String> entry:returnMap.entrySet()){
                        if(entry.getKey().contains(str)){
                            //有
                            flag = false;
                            break;
                        }
                    }
                    if(flag){
                        //没有
                        returnMap.put(str+(i+2), null);
                    }
                }
            }
        }
        return list;
    }


    /**
     * 封装数据
     * @param str
     * @param counts
     * @return
     */
    public static List<String> data(String str,int counts){
        List<String> list = new ArrayList<>();
        list.add(str);
        for(int i=0;i<counts;i++){
            strChar = str.toCharArray();
            jinwei(0);
            str = new String(strChar);
            list.add(str);
        }
        return list;
    }
    //数字进位
    public static void jinwei(int index){
        char a = 'A';
        int aint =(int)('A');
        if((strChar.length-1)-index>=0){
            int sc = (int)strChar[(strChar.length-1)-index];
            if(sc- 25 >= aint){
                jinwei(index+1);
                strChar[(strChar.length-1)-index] = a;
            }else{
                strChar[strChar.length-1-index] = (char)(sc+1);
            }
        }else{
            strChar[(strChar.length-1)-index+1] = a;
            StringBuilder str = new StringBuilder();
            str.append('A');
            str.append(strChar);
            strChar = str.toString().toCharArray();
        }
    }
}

快速获取总行数

package com.cignacmb.sms.common.util;


import java.io.InputStream;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
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.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;


/**
 * XSSF and SAX (Event API) basic example.
 * See {@link XLSX2CSV} for a fuller example of doing
 *  XSLX processing with the XSSF Event code.
 */
public class MaxRowExcelUtil {
    //new add
    public long maxRow = 0;//记录总行数

    private String filename = null;
    public MaxRowExcelUtil(String filename) throws Exception{
        if(StringUtils.isBlank(filename)) throw new Exception("文件名不能空");
        this.filename = filename;
        processFirstSheet();
    }
    /**
     * 指定获取第一个sheet
     * @param filename
     * @throws Exception
     */
    private void processFirstSheet() throws Exception {
        OPCPackage pkg = OPCPackage.open(filename);
        XSSFReader r = new XSSFReader( pkg );
        SharedStringsTable sst = r.getSharedStringsTable();

        XMLReader parser = fetchSheetParser(sst);

        // To look up the Sheet Name / Sheet Order / rID,
        //  you need to process the core Workbook stream.
        // Normally it's of the form rId# or rSheet#
        InputStream sheet2 = r.getSheet("rId1");
        InputSource sheetSource = new InputSource(sheet2);
        parser.parse(sheetSource);
        sheet2.close();
    }

    private XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException {
        XMLReader parser =
                XMLReaderFactory.createXMLReader(
                        "org.apache.xerces.parsers.SAXParser"
                );
        ContentHandler handler = new MaxRowHandler();
        parser.setContentHandler(handler);
        return parser;
    }

    /**
     * See org.xml.sax.helpers.DefaultHandler javadocs
     */
    private  class MaxRowHandler extends DefaultHandler {

        @Override
        public void startElement(String uri, String localName, String name,
                                 Attributes attributes) throws SAXException {
            // c => cell
            if(name.equals("c")) {
                String index = attributes.getValue("r");
                if(Pattern.compile("A[0-9]+$").matcher(index).find()){
                    maxRow++;
                }
            }
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容

  • 自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/mast...
    楷桐阅读 486评论 0 5
  • 机缘巧合发现的一份资源,在此感谢原作者(不知道是哪位大神)的分享 自定义控件学习https://github.co...
    Smart_Arvin阅读 1,126评论 0 20
  • 原创链接 一、Java面试题java有多重要,对于做android的我们,不需要多说了,let’s go (1)J...
    李福来阅读 2,286评论 0 5
  • https://github.com/XinYiWorld/CZSuperAdapters 欢迎使用 https:...
    奈何心善阅读 555评论 0 4
  • 钉钉(DingTalk)是阿里巴巴集团于2014年1月筹划启动,由阿里巴巴团队打造,专注于提升中国企业的办公与协同...
    _Sweet阅读 1,103评论 1 1