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”。
2.2、Workbook Document
Workbook文档可以包含多个sheet,每个Workbook文档都包含一个全局设置,叫做(workbook globals)。
3、OLE 2复合文档系统 - POIFS
就像上面展示的,xls实际上实际上以复合文档的形式组织在一起;然后POI以流的形式读取。
3.1、Workbook文件流 (Workbook Streams)
Workbook文件流会先读取workbook globals Substream,然后再依次读取每个Sheet Substream。
这里展示的是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