POI事件模式读取Excel 2007(三) - 解析步骤

一. 解析步骤

这里写图片描述

二. OPCPackage

当使用POI事件模式解析Excel XLSX文档时:

  1. POI根据xlsx文档的路径path获取到文件File - file
  2. 使用java.util.zip.ZipFile打开file文件 - zip
  3. 从zip中获取到[Content_Types].xml
  4. 解析[Content_Types].xml,记录解析出Excel各个xml名称:ArrayList
  5. Excel解析成ZipPackage实例对象

首先把xlsx文档解析包装成ZipPackage实例对象

package org.apache.poi.openxml4j.opc;

public enum PackageAccess {
    READ,   // 只读
    WRITE,  // 只写
    READ_WRITE // 读写
}

// 只读取xlsx文档
OPCPackage pkg = OPCPackage.open("C:\Users\Administrator\Desktop\测试.xlsx", PackageAccess.READ)

这里写图片描述

2.1 XLSX文档组成

Excel XLSX文档是有多个xml文件组成的,name各个xml是怎么组合在一起?POI是怎么来解析的呢?
在Excel文档中,存在一个[Content_Types].xml文档,这个文档记录了整个Excel文档中所有xml:
这里写图片描述

这里写图片描述

2.2 解析[Content_Types].xml

org.apache.poi.openxml4j.opc.internal.ContentTypeManager类用于解析[Content_Types].xml文档,记录解析出的结果

// ContentTypeManager解析方法
parseContentTypesFile(InputStream in)
<?xml version="1.0" encoding="UTF-8" standalone="true"?>

-<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">

<Default ContentType="application/vnd.openxmlformats-package.relationships+xml" Extension="rels"/>

<Default ContentType="application/xml" Extension="xml"/>

<Override ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" PartName="/docProps/app.xml"/>

<Override ContentType="application/vnd.openxmlformats-package.core-properties+xml" PartName="/docProps/core.xml"/>

<Override ContentType="application/vnd.openxmlformats-officedocument.custom-properties+xml" PartName="/docProps/custom.xml"/>

<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" PartName="/xl/styles.xml"/>

<Override ContentType="application/vnd.openxmlformats-officedocument.theme+xml" PartName="/xl/theme/theme1.xml"/>

<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" PartName="/xl/workbook.xml"/>

<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" PartName="/xl/worksheets/sheet1.xml"/>

<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" PartName="/xl/worksheets/sheet2.xml"/>

</Types>

这里写图片描述
解析结果:
这里写图片描述

2.3 解析出ZipPackage

Excel XLSX文档会被POI解析出ZipPackage实例对象:
这里写图片描述

3. XSSFReader

XSSFReader这个类可以很容易地获得OOXML .xlsx文件的各个部分,适用于低内存sax解析或类似的情况
XSSFReader构成了XSSF的事件模式的核心部分

org.apache.poi.xssf.eventusermodel.XSSFReader

// 获取当前Excel所有Sheet中字符串
public SharedStringsTable getSharedStringsTable()

// 获取当前Excel所有Sheet中单元格样式
public StylesTable getStylesTable()

// 获取sharedStrings.xml的输入流
public InputStream getSharedStringsData()

// 获取styles.xml输入流
public InputStream getStylesData()

// 获取theme1.xml输入流
public InputStream getThemesData()

// 获取workbook.xml输入流
public InputStream getWorkbookData()

// 根据Sheet的id获取Sheet输入流
public InputStream getSheet(String relId)

// 获取Excel中所有SHeet的输入流的迭代器
public Iterator<InputStream> getSheetsData()

这里写图片描述

4. SAX解析XML

使用SAX解析XML,需要实现自己的处理类,需要继承DefaultHandler

public class SheetHandler extends DefaultHandler {

    /**
     * 解析到XML的开始标签触发此方法
     * 
     * @param uri 如"http://schemas.openxmlformats.org/spreadsheetml/2006/main"
     * @param localName 当前开始标签的名字
     * @param name 标签名
     * @param attributes 当前标签的属性对象
     * */
    @Override
    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
        if ("row".equals(name)) {// <row>:开始处理某一行
            //
        } else if ("c".equals(name)) {// <c>:一个单元格
            //
        } else if (isTextTag(name)) {// <v>:单元格值
            // 
        } else if ("f".equals(name)) {// <f>:公式表达式标签
            //
        } else if ("is".equals(name)) {// 内联字符串外部标签
            // 
        } else if ("col".equals(name)) {// 处理隐藏列
            //
        } 
    }

    /**
     * 返回单元格的值
     * */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        StringBuffer sb = new StringBuffer();
        sb.append(ch, start, length);
    }

    /**
     * 解析到XML的结束标签触发此方法
     * 如:</row>
     * @param uri
     * @param localName
     * @param name
     * */
    @Override
    public void endElement(String uri, String localName, String name) throws SAXException {
        if ("c".equals(name)) {// <c>标签结束
            //
        } else if (isTextTag(name)) {// 文本单元格结束标签
            //
        } else if ("row".equals(name)) {// 行结束标签
            //
        } else if ("f".equals(name)) {// </f>标签
            //
        } else if ("is".equals(name)) {// </is>标签
            //
        } else if ("worksheet".equals(name)) {// Sheet读取完成
            // 
        }
    }
}

处理模型:

public class ExcelParser {
    public void parse () {
        OPCPackage pkg = OPCPackage.open("C:\\Users\\Administrator\\Desktop\\测试.xlsx", PackageAccess.READ);
        try {
            XSSFReader reader = new XSSFReader(pkg);
            SharedStringsTable sst = reader.getSharedStringsTable();
            StylesTable st = reader.getStylesTable();
            XMLReader parser = XMLReaderFactory.createXMLReader();
            // 处理公共属性:Sheet名,Sheet合并单元格
            parser.setContentHandler(new SheetHandler());
            /**
             * 返回一个迭代器,此迭代器会依次得到所有不同的sheet。 
             * 每个sheet的InputStream只有从Iterator获取时才会打开。 
             * 解析完每个sheet时关闭InputStream。
             * */
            XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) reader.getSheetsData();
            while (sheets.hasNext()) {
                InputStream sheetstream = sheets.next();
                InputSource sheetSource = new InputSource(sheetstream);
                try {
                    // 解析sheet: com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl:522
                    parser.parse(sheetSource);
                } finally {
                    sheetstream.close();
                }
            }
        } finally {
            pkg.close();
        }
    }
}
  • 8
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于使用POI库以event mode方式读取Excel文件,可以按照以下步骤进行: 1. 创建一个XSSFReader对象,该对象将Excel文件解析为XML格式。 2. 获取SharedStringsTable和StylesTable,这些表将在后面的步骤中用到。 3. 创建一个SheetContentsHandler对象,该对象将处理每个Sheet的内容。 4. 遍历所有的Sheet,将Sheet的InputStream传递给XSSFReader对象,并使用SheetContentsHandler处理Sheet的内容。 5. 关闭InputStream和XSSFReader对象。 下面是一个示例代码,用于演示如何使用event mode方式读取Excel文件: ```java import java.io.InputStream; import java.util.Iterator; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackageAccess; import org.apache.poi.xssf.eventusermodel.XSSFReader; import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler; import org.apache.poi.xssf.model.SharedStringsTable; import org.apache.poi.xssf.model.StylesTable; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; public class ExcelReader { public static void main(String[] args) throws Exception { String filename = "example.xlsx"; OPCPackage pkg = OPCPackage.open(filename, PackageAccess.READ); XSSFReader reader = new XSSFReader(pkg); SharedStringsTable sst = reader.getSharedStringsTable(); StylesTable styles = reader.getStylesTable(); SheetContentsHandler sheetHandler = new SheetContentsHandler(); XMLReader parser = XMLReaderFactory.createXMLReader(); parser.setContentHandler(new XSSFSheetXMLHandler(styles, sst, sheetHandler, false)); Iterator<InputStream> sheets = reader.getSheetsData(); while (sheets.hasNext()) { InputStream sheet = sheets.next(); InputSource sheetSource = new InputSource(sheet); parser.parse(sheetSource); sheet.close(); } pkg.close(); } } class SheetContentsHandler implements XSSFSheetXMLHandler.SheetContentsHandler { @Override public void startRow(int rowNum) { // TODO: 处理行的开始 } @Override public void endRow(int rowNum) { // TODO: 处理行的结束 } @Override public void cell(String cellReference, String formattedValue, XSSFComment comment) { // TODO: 处理单元格 } @Override public void headerFooter(String text, boolean isHeader, String tagName) { // TODO: 处理页眉、页脚 } } ``` 在上面的示例代码中,SheetContentsHandler是一个自定义的类,用于处理Sheet的内容。您可以根据自己的需求来实现SheetContentsHandler中的方法。另外,需要注意的是,event mode方式读取Excel文件是比较底层的操作,相对而言比较复杂,但是在读取大型Excel文件时,性能比基于DOM或SAX的方式更高效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值