POI事件模式读取Excel 2007(三)

来源:互联网 发布:国外网络电视台直播 编辑:程序博客网 时间:2024/06/05 16:07

一. 解析步骤

这里写图片描述

二. 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();        }    }}