POI事件模式指北(一)-Excel2003

简介: POI事件模式的第一篇,介绍了读取Excel2003 (.xls) 的相关知识。

POI事件模式指北(一)-Excel2003

1、简介

Excel2003(.xls)是Microsoft Excel2003之前版本要求的格式,POI提供两种方式读取这种类型的文件

1、用户模式(User API):将xls文件全部读进内存,然后以dom结构处理;

2、事件模式(event API):用流的形式读取文件,占用内存较少,适用于愿意学习低级API结构的开发人员,需要对Excel文件的各个部分有基本的了解。

2、XLS文件介绍

XLS后缀的文件包括Worksheet文档和Workbook文档两种。是Excel 4.0及以前版本为Worksheet文档;以后的版本为Workbook文档。

2.1、Worksheet Document

Worksheet文档只包括一个sheet,默认的文件后缀是“XLS”。

1550305595932

2.2、Workbook Document

Workbook文档可以包含多个sheet,每个Workbook文档都包含一个全局设置,叫做(workbook globals)。

1550306121698

3、OLE 2复合文档系统 - POIFS

就像上面展示的,xls实际上实际上以复合文档的形式组织在一起;然后POI以流的形式读取。

3.1、Workbook文件流 (Workbook Streams)

Workbook文件流会先读取workbook globals Substream,然后再依次读取每个Sheet Substream。

1550307124052

这里展示的是Workbook文档的文件流结构。鉴于我们基本不会遇到Worksheet Document,下面将只针对Workbook Document来讨论。更多相关信息请参见文末参考链接。

3.2、Workbook Records

文件中的各种流会以Record的形式被解析,每个Record都包含特定的数据和格式等相关信息。

例如BOFRecord记录了Workbook或Sheet的开始、EOFRecord记录了Workbook或Sheet的结束等等。。。

org.apache.poi.hssf.record包下面包括了各种Record类,我们需要的数据和文档结构就包含在各个Record类中。

我们常用的Record差不多有下面这些:

// 记录了sheetName
BoundSheetRecord
// Workbook、Sheet的开始
BOFRecord
// 存在单元格样式的空单元格
BlankRecord
// 布尔或错误单元格
BoolErrRecord
// 公式单元格
FormulaRecord
// 公式的计算结果单元格
StringRecord
// 文本单元格
LabelRecord
// 共用的文本单元格
LabelSSTRecord
// 数值单元格:数字单元格和日期单元格
NumberRecord
// Workbook、Sheet的结束
EOFRecord

4、解析文件

想要利用事件模式的API,需要将文件用FileSystem将文件读取进来

​ 1、继承HSSFListener接口,创建自己的监听器listener;

利用recordsid,recordsid是org.apache.poi.hssf.record中的类中包含的静态引用号(例如BOFRecord.sid)

​ 2、使用HSSFRequest.addListener(yourlistener,recordsid)注册监听器,也可以用HSSFRequest.addListenerForAllRecords(mylistener)添加全部监听器;

​ 3、构造org.apache.poi.poifs.filesystem.FileSystem的实例并将其传递给XLS文件输入流;

​ 4、将输入流DocumentInputStream解析成record;

​ 5、根据注册的监听类型分别处理各种类型的record;

4.1、org.apache.poi.hssf.eventusermodel.HSSFEventFactory

事件模式常用的方法一般是下面两个:

/**
* 将一个文件处理为基本的Record事件
* @param req 一个HSSFRequest实例,记录了Record的所有监听器
* @param fs 包含WorkBook的POIFS文件系统
*/
HSSFEventFactory.processWorkbookEvents(HSSFRequest req, POIFSFileSystem fs)
    
/**
* 将一个文件处理为基本的Record事件
* @param req 一个HSSFRequest实例,记录了Record的所有监听器
* @param in 包含WorkBook的DirectoryNode的输入流
*/
HSSFEventFactory.processEvents(HSSFRequest req, InputStream in)

5、事件模式实例

这个例子是参照POI官网提供的代码,针对的是POI最新的版本POI 4.0.1;但我们常用的3.x也基本都可以正常运行

EventExample.class

/**
 * 此示例显示如何使用事件API读取文件
 */
public class EventExample implements HSSFListener {
    
    private SSTRecord sstrec;

    /**
     * 此方法监听传入记录并根据需要处理它们
     * @param record读取时找到的记录
     */
    public void processRecord(Record record) {
        switch (record.getSid()) {
            //BOFRecord可以表示工作表或工作簿的开头
            case BOFRecord.sid:
                BOFRecord bof = (BOFRecord) record;
                if (bof.getType() == bof.TYPE_WORKBOOK) {
                    System.out.println("监听到工作表");
                } else if (bof.getType() == bof.TYPE_WORKSHEET) {
                    System.out.println("监听到工作簿");
                }
                break;
            case BoundSheetRecord.sid:
                BoundSheetRecord bsr = (BoundSheetRecord) record;
                System.out.println("工作簿名称: " + bsr.getSheetname());
                break;
            case RowRecord.sid:
                RowRecord rowrec = (RowRecord) record;
                System.out.println("监听到行, 第一行位于 "
                        + rowrec.getFirstCol() + " 最后一行位于 " + rowrec.getLastCol());
                break;
            case NumberRecord.sid:
                NumberRecord numrec = (NumberRecord) record;
                System.out.println("发现单元格: " + numrec.getValue()
                        + " 位于 " + numrec.getRow() + " 行, " + numrec.getColumn() + "                         列" );
                break; 
            case LabelSSTRecord.sid:
                LabelSSTRecord lrec = (LabelSSTRecord) record;
                System.out.println("找到文本值: "
                        + sstrec.getString(lrec.getSSTIndex()));
                break;
        }
    }

    / **
     * 读取Excel文件,并打印出文件内容
     * @param args 要读取的文件
     * @throws IOException
     * / 
    public static void main(String[] args) throws IOException {
        // 使用输入的文件创建一个新的文件输入流
        FileInputStream fin = new FileInputStream(args[0]);
        // 创建一个新的org.apache.poi.poifs.filesystem.Filesystem 
        POIFSFileSystem poifs = new POIFSFileSystem(fin);
        // 在InputStream中获取Workbook流
        InputStream din = poifs.createDocumentInputStream("Workbook");
        // 构造出HSSFRequest对象
        HSSFRequest req = new HSSFRequest();
        // 注册全部的监听器
        req.addListenerForAllRecords(new EventExample());
        // 创建事件工厂
        HSSFEventFactory factory = new HSSFEventFactory();
        // 根据文档输入流处理我们监听的事件
        factory.processEvents(req, din);
        // 关闭文件输入流
        fin.close();
        // 关闭文档输入流
        din.close();
        System.out.println("读取结束");
    }
}

6、后记

本文主要介绍了利用POI读取xls文件,xls文件因为是Excel2003以前的版本都使用的格式,其实不同版本之间还是有一些不同的,如果遇到了奇怪的问题不妨考虑一下版本的问题。这篇文章没有涉及d的实用部分,会在之后的文章中写出来。


参考链接
Apache POI官网: https://poi.apache.org
XLS规范[PDF]: http://www.openoffice.org/sc/excelfileformat.pdf

相关文章
|
7月前
|
API
Poi 中文API文档 「40种操作 Excel文件的姿势」
Poi 中文API文档 「40种操作 Excel文件的姿势」
320 0
|
7月前
|
easyexcel Java 测试技术
读取Excel还用POI?试试这款开源工具EasyExcel
读取Excel还用POI?试试这款开源工具EasyExcel
186 0
|
Java Maven
【Java用法】使用poi写Java代码导出Excel文档的解决方案
【Java用法】使用poi写Java代码导出Excel文档的解决方案
88 0
|
2月前
|
前端开发 JavaScript Java
导出excel的两个方式:前端vue+XLSX 导出excel,vue+后端POI 导出excel,并进行分析、比较
这篇文章介绍了使用前端Vue框架结合XLSX库和后端结合Apache POI库导出Excel文件的两种方法,并对比分析了它们的优缺点。
494 0
|
2月前
|
Java Apache
Apache POI java对excel表格进行操作(读、写) 有代码!!!
文章提供了使用Apache POI库在Java中创建和读取Excel文件的详细代码示例,包括写入数据到Excel和从Excel读取数据的方法。
48 0
|
6月前
|
Java API Spring
集成EasyPoi(一个基于POI的Excel导入导出工具)到Spring Boot项目中
集成EasyPoi(一个基于POI的Excel导入导出工具)到Spring Boot项目中
564 1
|
6月前
|
easyexcel Java API
Apache POI与easyExcel:Excel文件导入导出的技术深度分析
Apache POI与easyExcel:Excel文件导入导出的技术深度分析
|
7月前
【POI】常用excel操作方法
【POI】常用excel操作方法
63 1
|
7月前
|
Java Apache 索引
POI操作大全(动态合并单元格,为单元格生成一个自定义的数据显示格式,自定义公式计算结果生成,读取excel,word文件在生成图片,word指定位置生成图片)
POI操作大全(动态合并单元格,为单元格生成一个自定义的数据显示格式,自定义公式计算结果生成,读取excel,word文件在生成图片,word指定位置生成图片)
993 0
|
7月前
|
Java
POI上传excel的java后台逻辑
POI上传excel的java后台逻辑