使用SAXReader方式解析excel

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;import javax.xml.XMLConstants;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;/*** @author tkgup* @since 2021/5/29*/
public class MyHandler extends DefaultHandler {private static final String empty = "";// 样式数据private final StylesTable stylesTable;// 取SST的索引对应的值private final ReadOnlySharedStringsTable sst;// 解析结果保存private final List<List<String>> container;// 是否忽略中单的空行private final boolean undividedData;// 存储cell标签下v标签包裹的字符文本内容// 在v标签开始后,解析器自动调用characters()保存到 cellValue// 但当cell标签的属性 s是 t时, 表示取到的cellValue是SharedStringsTable 的index值// 需要在v标签结束时根据 index(cellValue)获取一次真正的值private String cellValue;// 记录数据类型private DataType nextDataType;// 根据dimension得出最大列private int maxColumn;// 根据dimension得出总行数private int maxRow;// 需要解析的列数private int parseColumn;// 需要解析的行数private int parseRow;// 上个有内容的单元格id,判断空单元格private Integer preCellIndex;// 当前行id,判断空行private Integer rowId;// 判断单元格cell的c标签下是否有v,否则可能数据错位private boolean hasV;// 行数据保存private List<String> currentRowData;public MyHandler(ReadOnlySharedStringsTable sst, StylesTable stylesTable,List<List<String>> container) {this(sst, stylesTable, container, -1);}public MyHandler(ReadOnlySharedStringsTable sst, StylesTable stylesTable,List<List<String>> container, int parseRow) {this(sst, stylesTable, container, parseRow, -1);}public MyHandler(ReadOnlySharedStringsTable sst, StylesTable stylesTable,List<List<String>> container, int parseRow, int parseColumn) {this(sst, stylesTable, container, parseRow, parseColumn, false);}public MyHandler(ReadOnlySharedStringsTable sst, StylesTable stylesTable,List<List<String>> container, int parseRow, int parseColumn, boolean undividedData) {this.stylesTable = stylesTable;this.sst = sst;this.container = container;this.parseRow = parseRow;this.parseColumn = parseColumn;this.undividedData = undividedData;}public static void main(String[] args) throws Exception {String filePath = "日记.xlsx";List<List<String>> sheet = parse(filePath);System.out.println();for (List<String> row : sheet) {System.out.println(String.join(",", row));}System.out.println();}private static List<List<String>> parse(String filePath)throws Exception {//将文件以压缩包的形式读入OPCPackage opcPackage = OPCPackage.open(filePath, PackageAccess.READ);ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(opcPackage, false);//读入样式信息XSSFReader xssfReader = new XSSFReader(opcPackage);//这里只读入了第一个sheet,如果需要读取多个可以遍历这个迭代器InputStream stream = xssfReader.getSheetsData().next();//构造XLSXReader读取内容List<List<String>> container = parse(xssfReader.getStylesTable(), strings, stream);//关闭流stream.close();opcPackage.close();return container;}private static List<List<String>> parse(StylesTable styles, ReadOnlySharedStringsTable strings,InputStream sheetInputStream) throws Exception {//将输入流包装成XML源InputSource sheetSource = new InputSource(sheetInputStream);//构造基于标签回调的XMLReaderSAXParserFactory factory = getSafeSaxParserFactory();SAXParser saxParser = factory.newSAXParser();XMLReader reader = saxParser.getXMLReader();List<List<String>> container = new ArrayList<>();//构造XLSXReaderMyHandler handler = new MyHandler(strings, styles, container, 3, 5, true);//添加管理者reader.setContentHandler(handler);//读入XML源try {reader.parse(sheetSource);} catch (ParseRuntimeException e) {doNothing();} catch (IOException | SAXException e) {throw new RuntimeException("解析数据时发生异常");}return container;}private static SAXParserFactory getSafeSaxParserFactory()throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException {SAXParserFactory factory = SAXParserFactory.newInstance();factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);factory.setFeature("http://xml.org/sax/features/external-general-entities", false);factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);return factory;}private static int getColumnNumByCellIndex(String cellId) {return parseColumn(cellId.substring(0, getRowNumberIndex(cellId)));}private static int getRowNumByCellIndex(String cellId) {return Integer.parseInt(cellId.substring(getRowNumberIndex(cellId)));}private static int parseColumn(String columnId) {// 列号字符转数字int result = 0;for (char num : columnId.toCharArray()) {result = result * 26 + ((num - 'A') + 1);}return result;}private static int getRowNumberIndex(String cellId) {int firstDigit = -1;for (int i = 0; i < cellId.length(); i++) {if (Character.isDigit(cellId.charAt(i))) {firstDigit = i;break;}}return firstDigit;}private static void doNothing() {}@Overridepublic void startElement(String uri, String localName, String qName, Attributes attributes) {// 置空上一个单元格保存的内容,准备保存当前单元格的cellValue = empty;if ("dimension".equals(qName)) {String dimension = attributes.getValue("ref");String endCell = dimension.substring(dimension.indexOf(":") + 1);maxColumn = getColumnNumByCellIndex(endCell);maxRow = getRowNumByCellIndex(endCell);parseColumn = parseColumn < 0 ? maxColumn : parseColumn;parseRow = parseRow < 0 ? maxRow : parseRow;}// 行开始if ("row".equals(qName)) {preCellIndex = null;int rowNum = Integer.parseInt(attributes.getValue("r"));checkReadRow(rowNum);addEmptyRow(rowNum);currentRowData = new ArrayList<>();}// 单元格if ("c".equals(qName)) {int cellIndex = getColumnNumByCellIndex(attributes.getValue("r"));fillRowMidEmpty(cellIndex);preCellIndex = cellIndex;nextDataType = DataType.getDataType(attributes, stylesTable);}}@Overridepublic void characters(char[] ch, int start, int length) throws SAXException {cellValue += new String(ch, start, length);}@Overridepublic void endElement(String uri, String localName, String qName) {if ("row".equals(qName)) {fillRowTailEmpty();checkAddRow();}if ("c".equals(qName)) {if (!hasV) {checkAdd(empty);}hasV = false;}if ("v".equals(qName)) {hasV = true;checkAdd(nextDataType.dealValue(sst, cellValue));}}private void checkAddRow() {if (undividedData) {container.add(currentRowData);return;}for (String cellV : currentRowData) {if (Optional.ofNullable(cellV).orElse("").length() > 0) {container.add(currentRowData);return;}}}private void checkAdd(String cellValue) {if (currentRowData.size() < parseColumn) {currentRowData.add(cellValue);}}private void checkReadRow(int rowNum) {if (parseRow >= 0 && rowNum - 1 >= parseRow) {// 用于达到指定行数时中断解析操作if (undividedData || container.size() >= parseRow) {throw new ParseRuntimeException();}}}private void addEmptyRow(int rowNum) {if (undividedData && rowId != null) {//与上一行相差2, 说明中间有空行int gap = rowNum - rowId;while (gap-- > 1) {container.add(Collections.nCopies(parseColumn, empty));}}rowId = rowNum;}private void fillRowMidEmpty(int cellIndex) {// 空单元判断,填充空字符到listint leftColumn = Math.min(cellIndex, parseColumn);if (preCellIndex != null) {// 解析的单元格 非 此行第一个有值单元格int gap = leftColumn - preCellIndex;// 为中间间隙填值for (int i = 0; i < gap - 1; i++) {currentRowData.add(empty);}} else {// 解析的单元格 为 此行第一个有值单元格// 非第一个单元格时为前面的补值if (leftColumn != 1) {for (int i = 0; i < leftColumn - 1; i++) {currentRowData.add(empty);}}}}private void fillRowTailEmpty() {// 判断最后一个单元格是否在最后,补齐列数// 有的单元格只修改单元格格式,而没有内容,会出现c标签下没有v标签,导致currentRow少int dataSize = currentRowData.size();for (int i = 0; i < parseColumn - dataSize; i++) {currentRowData.add(empty);}}enum DataType {BOOL("b") {@Overridepublic String dealValue(ReadOnlySharedStringsTable sst, String cellValue) {return cellValue.charAt(0) == 'A' ? "false" : "true";}},ERROR("e") {@Overridepublic String dealValue(ReadOnlySharedStringsTable sst, String cellValue) {return cellValue;}},FORMULA("str") {@Overridepublic String dealValue(ReadOnlySharedStringsTable sst, String cellValue) {return cellValue;}},INLINE_STR("inlineStr") {@Overridepublic String dealValue(ReadOnlySharedStringsTable sst, String cellValue) {return new XSSFRichTextString(cellValue).toString();}},SST_INDEX("s") {@Overridepublic String dealValue(ReadOnlySharedStringsTable sst, String cellValue) {return sst.getItemAt(Integer.parseInt(cellValue)).toString();}},NUMBER("d") {@Overridepublic String dealValue(ReadOnlySharedStringsTable sst, String cellValue) {return cellValue;}},STYLE("") {@Overridepublic String dealValue(ReadOnlySharedStringsTable sst, String cellValue) {if (DateUtil.isADateFormat(formatIndex, formatString)) {return dateFormat.format(DateUtil.getJavaDate(Double.parseDouble(cellValue)));}if (formatString != null) {return formatter.formatRawCellContents(Double.parseDouble(cellValue), formatIndex, formatString);}return cellValue;}};protected static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");protected static final DataFormatter formatter = new DataFormatter();protected short formatIndex;protected String formatString;private final String desc;DataType(String desc) {this.desc = desc;}public static DataType getDataType(Attributes attributes, StylesTable stylesTable) {String cellType = attributes.getValue("t");for (DataType type : values()) {if (type.desc.equals(cellType)) {return type;}}String cellStyleStr = attributes.getValue("s");if (cellStyleStr != null) {XSSFCellStyle style = stylesTable.getStyleAt(Integer.parseInt(cellStyleStr));short formatIndex = style.getDataFormat();STYLE.formatIndex = formatIndex;STYLE.formatString = Optional.ofNullable(style.getDataFormatString()).orElse(BuiltinFormats.getBuiltinFormat(formatIndex));return STYLE;}return NUMBER;}public abstract String dealValue(ReadOnlySharedStringsTable sst, String cellValue);}static class ParseRuntimeException extends RuntimeException {private static final long serialVersionUID = 3582523992040854628L;}
}

使用SAXReader以XML方式解析excel相关推荐

  1. SAX方式实现Excel导入

    SAX解析Excel 上篇讲到了DOM解析Excel , 这篇记录工作中用到的SAX方式解析Excel的封装实现, 说明: 以下代码基于poi-3.17版本实现, poi-3.17及以上版本相比3.1 ...

  2. POI解析Excel表格

    Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. 这里实现poi解析Excel表格的例子,导入Exc ...

  3. Java解析xml文件dom4j篇(基于xml配置文件完成Excel数据的导入、导出功能完整实现)

    DOM4J解析XML文件 dom4j是一个Java的XML API,是jdom的升级产品,用来读写XML文件.另外对比其他API读写XML文件,dom4j是一个十分优秀的JavaXML API,具有性 ...

  4. XML文件解析-DOM4J方式和SAX方式

    最近遇到的工作内容都是和xml内容解析相关的. 1图片数据以base64编码的方式保存在xml的一个标签中,xml文件通过接口的方式发送给我,然后我去解析出图片数据,对图片进行进一步处理. 2.xml ...

  5. POI读取excel百万级-SAX方式解析

    一. 简介 在excel解析的时候,采用SAX方方式会将excel转换为xml进行解析避免了内存溢出. 速度在3秒1W的数据写入,100W条记录,大概50M的数据,耗时大概4分半(如果不需要校验,可能 ...

  6. Android网络之数据解析----SAX方式解析XML数据

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  7. 解析XML方式-DOM,SAX

    students.xml <?xml version="1.0" encoding="UTF-8"?> <students><st ...

  8. 用SAX2方式解析XML

    SAX2 Qt 的 SAX 类基于 SAX2 的 Java 实现,不过具有一些必要的名称上的转换.相比 DOM,SAX 的实现更底层因而处理起来通常更快.但是,我们前面介绍的QXmlStreamRea ...

  9. php 解析返回的xml,php解析xml的几种方式

    php提供几种解析xml的类或方法,包括:Xml parser. SimpleXML,.XMLReader,.DOMDocument. XML Expat Parser: XML Parser使用Ex ...

  10. Unity 基础 之 xml 使用 Office Excel 轻松编辑保存 xml 数据,并解析读取数据

    Unity 基础 之 xml  使用 Office Excel 轻松编辑保存 xml 数据 目录 Unity 基础 之 xml  使用 Office Excel 轻松编辑保存 xml 数据 一.简单介 ...

最新文章

  1. amd一点也不yes_AMD, 真的YES吗?
  2. Kafka如果丢了消息,怎么处理的?
  3. v3s修改驱动代码的流程
  4. carsim学习笔记3——仿真环境(驾驶员道路环境)
  5. idea java添加属性快捷键_Intellij IDEA 常用 设置 及 快捷键 (持续更新)
  6. 逻辑回归python正则化 选择参数_吴恩达机器学习笔记(三)——正则化(Regularization)...
  7. matlab问题利用M文件比较两个数大小,Matlab中写M文件及调用
  8. Applied Functional Analysis(Applications to Mathematical Physics ) E.Zeidler
  9. java中double类型占几个字节_面试官:Java 中有几种基本数据类型是什么?各自占用多少字节?...
  10. SAP License:云ERP真的已经玩不转了吗?
  11. zuul压力测试与调优
  12. 【UVA524】Prime Ring Problem(素数环--递归回溯+全局变量的一个小坑点---水题)
  13. Qt获取本机硬盘序列号,不受IDE硬盘与SCSI硬盘类型影响
  14. 根据年、月、周、日设置时间节点的日期工具类
  15. springboot+vue整合百度的Ueditor(保姆级教程)
  16. top20万_主播收入榜(9.28)| 陌陌主播叶哥收入50万夺冠
  17. 【2023王道数据结构】【树与二叉树】通过C++实现中序遍历的非递归算法(手动入出栈)C、C++完整实现(可直接运行
  18. 如何结束python程序_python程序结束
  19. 概率论与数理统计(第二章---随机变量及其分布函数
  20. shell综合练习(二)

热门文章

  1. 首次!让我们出一个基于延迟的同行 IP 库数据评估来打个样~
  2. Windows10(MSN)天气数据爬取
  3. 计算机无法打印图片,电脑中打印机可以打印文档却无法打印图片如何解决
  4. 【PyQt5】串口数据实时绘图
  5. 弹簧优化设计MATLAB,基于Matlab的圆柱螺旋弹簧可靠性优化设计
  6. 原生js用ajax上传图片,关于js ajax上传图片
  7. 如何为java添加日历控件_laydate日历控件使用方法详解
  8. 已知鸡兔共35只c语言,三支一扶行测备考数量关系:简单计算之鸡兔同笼
  9. phpQuery使用经验,抓取网页快捷,拒绝正则表达式
  10. 嵌入式C语言volatile作用