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

相关文章
|
1月前
|
easyexcel Java 测试技术
读取Excel还用POI?试试这款开源工具EasyExcel
读取Excel还用POI?试试这款开源工具EasyExcel
57 0
|
2月前
|
API
Poi 中文API文档 「40种操作 Excel文件的姿势」
Poi 中文API文档 「40种操作 Excel文件的姿势」
120 0
|
6月前
|
Java Maven
【Java用法】使用poi写Java代码导出Excel文档的解决方案
【Java用法】使用poi写Java代码导出Excel文档的解决方案
58 0
|
2月前
|
Java
POI上传excel的java后台逻辑
POI上传excel的java后台逻辑
|
2月前
|
Java
使用POI导出Excel
使用POI导出Excel
|
3月前
|
缓存 Java 关系型数据库
Java使用POI操作Excel
Java使用POI操作Excel
34 0
|
8月前
|
存储 Java BI
探索Apache POI库:强大的Excel和Word文档处理工具
在企业应用和数据处理中,Excel和Word文档是常见的数据交换和存储格式。然而,处理和操作这些文档可能是一项繁琐的任务。Apache POI库作为一款强大的文档处理工具,可以帮助我们更轻松地进行Excel和Word文档的读写、编辑和生成。本文将深入探讨Apache POI库的基本概念、特点,以及如何在实际应用中使用它进行文档处理。
406 0
|
4月前
|
XML 存储 Java
Apache POI 实现用Java操作Excel完成读写操作
Apache POI 实现用Java操作Excel完成读写操作
|
4月前
POI(excel)中表格(单元格)样式应用实践总结
POI(excel)中表格(单元格)样式应用实践总结
39 0