- 浏览: 7338859 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (1546)
- 企业中间件 (236)
- 企业应用面临的问题 (236)
- 小布Oracle学习笔记汇总 (36)
- Spring 开发应用 (54)
- IBatis开发应用 (16)
- Oracle基础学习 (23)
- struts2.0 (41)
- JVM&ClassLoader&GC (16)
- JQuery的开发应用 (17)
- WebService的开发应用 (21)
- Java&Socket (44)
- 开源组件的应用 (254)
- 常用Javascript的开发应用 (28)
- J2EE开发技术指南 (163)
- EJB3开发应用 (11)
- GIS&Mobile&MAP (36)
- SWT-GEF-RCP (52)
- 算法&数据结构 (6)
- Apache开源组件研究 (62)
- Hibernate 学习应用 (57)
- java并发编程 (59)
- MySQL&Mongodb&MS/SQL (15)
- Oracle数据库实验室 (55)
- 搜索引擎的开发应用 (34)
- 软件工程师笔试经典 (14)
- 其他杂项 (10)
- AndroidPn& MQTT&C2DM&推技术 (29)
- ActiveMQ学习和研究 (38)
- Google技术应用开发和API分析 (11)
- flex的学习总结 (59)
- 项目中一点总结 (20)
- java疑惑 java面向对象编程 (28)
- Android 开发学习 (133)
- linux和UNIX的总结 (37)
- Titanium学习总结 (20)
- JQueryMobile学习总结 (34)
- Phonegap学习总结 (32)
- HTML5学习总结 (41)
- JeeCMS研究和理解分析 (9)
最新评论
-
lgh1992314:
[u][i][b][flash=200,200][url][i ...
看看mybatis 源代码 -
尼古拉斯.fwp:
图片根本就不出来好吧。。。。。。
Android文件图片上传的详细讲解(一)HTTP multipart/form-data 上传报文格式实现手机端上传 -
ln94223:
第一个应该用排它网关吧 怎么是并行网关, 并行网关是所有exe ...
工作流Activiti的学习总结(八)Activiti自动执行的应用 -
ZY199266:
获取不到任何消息信息,请问这是什么原因呢?
ActiveMQ 通过JMX监控Connection,Queue,Topic的信息 -
xiaoyao霄:
DestinationSourceMonitor 报错 应该导 ...
ActiveMQ 通过JMX监控Connection,Queue,Topic的信息
POI3.8组件研究(四)--Event API (HSSF Only)事件的解析
通过eventusermodel读取文件
通过eventusermodel读取文件要比使用usermodel复杂得多,但效率也要高不少,因为它要求应用程序一边读取数据,一边处理数据。
eventusermodel实际上模拟了DOM环境下SAX处理XML文档的办法,应用程序首先要注册期望处理的数据,eventusermodel将在遇到匹配的数据结构时回调应用程序注册的方法。使用eventusermodel最大的困难在于你必须熟悉Excel工作簿的内部结构。
在HSSF中,低层次的二进制结构称为记录(Record)。记录有不同的类型,每一种类型由org.apache.poi.hssf.record包中的一个Java类描述。例如,BOFRecord记录表示Workbook或Sheet区域的开始,RowRecord表示有一个行存在并保存其样式信息。
所有具有CellValueRecordInterface接口的记录表示Excel的单元格,包括NumericRecord、LabelSSTRecord和FormulaRecord(还有其他一些,其中部分已被弃置不用,部分用于优化处理,但一般而言,HSSF可以转换它们)。
解析Excel2003 的event user-model必须继承 HSSFListener;
public class UserModelEventListener implements HSSFListener ;
package com.easyway.excel.events; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener; import org.apache.poi.hssf.eventusermodel.HSSFListener; import org.apache.poi.hssf.record.BOFRecord; import org.apache.poi.hssf.record.BlankRecord; import org.apache.poi.hssf.record.BoolErrRecord; import org.apache.poi.hssf.record.BoundSheetRecord; import org.apache.poi.hssf.record.FormulaRecord; import org.apache.poi.hssf.record.LabelSSTRecord; import org.apache.poi.hssf.record.NumberRecord; import org.apache.poi.hssf.record.RowRecord; import org.apache.poi.hssf.record.SSTRecord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 基于POI HSSF的eventmodel 模型的时间解析方式 * 优点:解析数据相当快。 * 缺点:1.仅仅支持97~2003版本的excel,不支持2007版本的excel。 * 2.只能读Excel中一个Sheet页面。 * * @Title: * @Description: 实现TODO * @Copyright:Copyright (c) 2011 * @Company:易程科技股份有限公司 * @Date:2012-6-14 * @author longgangbai * @version 1.0 */ public class UserModelEventListener implements HSSFListener { private static Logger logger=LoggerFactory.getLogger(UserModelEventListener.class); private SSTRecord sstrec; /** Should we output the formula, or the value it has? */ private boolean outputFormulaValues = true; /** For parsing Formulas */ private SheetRecordCollectingListener workbookBuildingListener; //当前Sheet的内容 private List<Map<String,Object>> currentSheetDataMap=new ArrayList<Map<String,Object>>(); //列对应的字段 private static String[] trianListheadTitle=new String[]{"trainCode","firstStation","lastStation","startStation","arriveStation","startTime","arriveTime","fistLevelPrice","secondLevelPrice","km","useDate"}; //一行记录 private Map<String,Object> currentSheetRowDataMap=new HashMap<String,Object>(); private int curRowNum=0; private int ignoreRowNum=1; private int sheetNo=0; @Override public void processRecord(org.apache.poi.hssf.record.Record record) { switch (record.getSid()) { case BOFRecord.sid: BOFRecord bof = (BOFRecord) record; //顺序进入新的Workbook if (bof.getType() == bof.TYPE_WORKBOOK) { logger.debug("开始解析excel 文档....."); //顺序进入新的Worksheet,因为Event API不会把Excel文件里的所有数据结构都关联起来, //所以这儿一定要记录现在进入第几个sheet了。 } else if (bof.getType() == bof.TYPE_WORKSHEET) { //读取新的一个Sheet页 logger.debug("开始解析sheet页面内容..."); System.out.println("sheetNo="+sheetNo); sheetNo++; currentSheetDataMap=new ArrayList<Map<String,Object>>(); } break; //开始解析Sheet的信息,记录sheet,这儿会把所有的sheet都顺序打印出来,如果有多个sheet的话,可以顺序记入到一个List里 case BoundSheetRecord.sid: BoundSheetRecord bsr = (BoundSheetRecord) record; System.out.println("sheetName="+bsr.getSheetname()); logger.debug("New sheet named: " + bsr.getSheetname()); break; //执行行记录事件 case RowRecord.sid: RowRecord rowrec = (RowRecord) record; logger.debug("记录开始, first column at " + rowrec.getFirstCol() + " last column at " + rowrec.getLastCol()); break; // SSTRecords store a array of unique strings used in Excel. case SSTRecord.sid: sstrec = (SSTRecord) record; for (int k = 0; k < sstrec.getNumUniqueStrings(); k++) { logger.debug("String table value " + k + " = " + sstrec.getString(k)); } break; //发现数字类型的cell,因为数字和日期都是用这个格式,所以下面一定要判断是不是日期格式,另外默认的数字也会被视为日期格式,所以如果是数字的话,一定要明确指定格式!!!!!!! case NumberRecord.sid: NumberRecord nr = (NumberRecord) record; //HSSFDateUtil.isInternalDateFormat(nr.getXFIndex()) 判断是否为时间列 int column=nr.getColumn(); if(column==5||column==6){ addDataAndrChangeRow(nr.getRow(),nr.getColumn(),getTime(nr.getValue())); }else{ addDataAndrChangeRow(nr.getRow(),nr.getColumn(),(int)nr.getValue()); } break; //发现字符串类型,这儿要取字符串的值的话,跟据其index去字符串表里读取 case LabelSSTRecord.sid: LabelSSTRecord lsr = (LabelSSTRecord)record; addDataAndrChangeRow(lsr.getRow(),lsr.getColumn(), sstrec.getString(lsr.getSSTIndex())); logger.debug("文字列:"+sstrec.getString(lsr.getSSTIndex())+", 行:"+lsr.getRow()+", 列:"+lsr.getColumn()); break; case BoolErrRecord.sid: //解析boolean错误信息 BoolErrRecord ber = (BoolErrRecord)record; if(ber.isBoolean()){ addDataAndrChangeRow(ber.getRow(),ber.getColumn(), ber.getBooleanValue()); logger.debug("Boolean:"+ber.getBooleanValue()+", 行:"+ber.getRow()+", 列:"+ber.getColumn()); } if(ber.isError()){ logger.debug("Error:"+ber.getErrorValue()+", 行:"+ber.getRow()+", 列:"+ber.getColumn()); } break; //空白记录的信息 case BlankRecord.sid: BlankRecord br = (BlankRecord)record; addDataAndrChangeRow(br.getRow(),br.getColumn(), ""); logger.debug("空。 行:"+br.getRow()+", 列:"+br.getColumn()); break; case FormulaRecord.sid: //数式 FormulaRecord fr = (FormulaRecord)record; addDataAndrChangeRow(fr.getRow(),fr.getColumn(), fr.getValue()); logger.debug("数字 。 行:"+fr.getRow()+", 列:"+fr.getColumn()); break; } } /** * HH:MM格式时间的数字转换方法</li> * @param sNum * @return */ private static String getTime(double daynum) { double totalSeconds=daynum*86400.0D; //总的分钟数 int seconds =(int)totalSeconds/60; //实际小时数 int hours =seconds/60; int minutes = seconds-hours*60; //剩余的实际分钟数 StringBuffer sb=new StringBuffer(); if(String.valueOf(hours).length()==1){ sb.append("0"+hours); }else{ sb.append(hours); } sb.append(":"); if(String.valueOf(minutes).length()==1){ sb.append("0"+minutes); }else{ sb.append(minutes); } return sb.toString(); } /** * 添加数据记录并检查是否换行 * @param row 实际当前行号 * @param col 实际记录当前列 * @param value 当前cell的值 */ public void addDataAndrChangeRow(int row,int col,Object value){ //当前行如果大于实际行表示改行忽略,不记录 if(curRowNum!=row){ if(CollectionUtils.isEmpty(currentSheetDataMap)){ currentSheetDataMap=new ArrayList<Map<String,Object>>(); } currentSheetDataMap.add(currentSheetRowDataMap); logger.debug("行号:"+curRowNum +" 行内容:"+currentSheetRowDataMap.toString()); logger.debug("\n"); currentSheetRowDataMap=new HashMap<String,Object>(); currentSheetRowDataMap.put(trianListheadTitle[col], value); logger.debug(row+":"+col+" "+value+"\r"); curRowNum=row; }else{ currentSheetRowDataMap.put(trianListheadTitle[col], value); logger.debug(row+":"+col+" "+value+"\r"); } } public List<Map<String, Object>> getCurrentSheetDataMap() { return currentSheetDataMap; } public void setCurrentSheetDataMap(List<Map<String, Object>> currentSheetDataMap) { this.currentSheetDataMap = currentSheetDataMap; } public Map<String, Object> getCurrentSheetRowDataMap() { return currentSheetRowDataMap; } public void setCurrentSheetRowDataMap(Map<String, Object> currentSheetRowDataMap) { this.currentSheetRowDataMap = currentSheetRowDataMap; } public int getCurRowNum() { return curRowNum; } public void setCurRowNum(int curRowNum) { this.curRowNum = curRowNum; } public int getIgnoreRowNum() { return ignoreRowNum; } public void setIgnoreRowNum(int ignoreRowNum) { this.ignoreRowNum = ignoreRowNum; } }
测试代码如下:
package com.easyway.excel.events; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Map; import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; import org.apache.poi.hssf.eventusermodel.HSSFEventFactory; import org.apache.poi.hssf.eventusermodel.HSSFRequest; import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener; import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener; import org.apache.poi.poifs.filesystem.POIFSFileSystem; public class UserModelEventMain { /** * 解析Excel2003的事件解析格式 * @param args * @throws IOException */ public static void main(String[] args) throws IOException { UserModelEventListener xlsEventListener=new UserModelEventListener(); MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener( xlsEventListener); FormatTrackingHSSFListener formatListener = new FormatTrackingHSSFListener(listener); //创建一个excel输入流 FileInputStream fin = new FileInputStream("C:\\station2station.xls"); //创建一个 org.apache.poi.poifs.filesystem.Filesystem POIFSFileSystem poifs = new POIFSFileSystem(fin); //将excel 2003格式POI文档输入流 InputStream din = poifs.createDocumentInputStream("Workbook"); //这儿为所有类型的Record都注册了监听器,如果需求明确的话,可以用addListener方法,并指定所需的Record类型 HSSFRequest req = new HSSFRequest(); //添加监听记录的事件 req.addListenerForAllRecords(xlsEventListener); boolean outputFormulaValues=true; if (outputFormulaValues) { req.addListenerForAllRecords(formatListener); } else { SheetRecordCollectingListener workbookBuildingListener = new SheetRecordCollectingListener( formatListener); req.addListenerForAllRecords(workbookBuildingListener); } //创建时间工厂 HSSFEventFactory factory = new HSSFEventFactory(); //处理基于时间文档流 factory.processEvents(req, din); //关闭文件流 fin.close(); //关闭基于POI文档流 din.close(); List<Map<String, Object>> sheetDataList=xlsEventListener.getCurrentSheetDataMap(); System.out.println("Excel Sheet记录数"+sheetDataList.size()+" 内容"+sheetDataList.toString()); } }
测试excel文件如下:
- station2station.zip (9.1 KB)
- 下载次数: 179
发表评论
-
【转】Django resources
2014-01-23 14:35 10827Django resources This page li ... -
使用国内镜像源来加速python pypi包的安装
2014-01-16 11:16 197842pipy国内镜像目前有: http://pypi.d ... -
[转 ]vagrant使用简介
2014-01-10 13:53 257501> 简介: vagrant提供了易于配置,重复性 ... -
[转]在Java中调用Python
2014-01-07 13:08 9219在执行之前都需要把jython对应的包加载进去,这个是必须的 ... -
[转]Jython初探
2014-01-07 11:19 2409转载自: ... -
[转]Eclipse配置PyDev插件
2014-01-02 14:25 2839安装python解释器 安装PyDev: 首 ... -
RestFuse的研究(五) Http请求的封装
2014-06-14 15:50 3647在RestFuse中封装了Http请 ... -
RestFuse的研究(四) Junit的Statement的分析
2013-12-06 11:46 1673在RestFuse提供了多种单 ... -
RestFuse的研究(三) Junit的Rule的使用和分析
2013-12-06 11:01 2238在junit中定义一些可以公用的规则(R ... -
RestFuse的研究(二) Junit的Runner的分类和模式
2013-12-06 10:40 1604在Junit4中的调用JunitCore可以采 ... -
RestFuse的研究(一) HttpJunitRunner的实现
2013-12-06 10:11 1747在RestFuse是一种针对Rest We ... -
[转]An open-source JUnit extension to test HTTP/REST APIs
2013-12-06 09:57 1100http://developer.eclipsesource ... -
TestNG简单的学习(十三)TestNG中Junit的实现
2013-12-04 09:00 3355TestNG和junit的整合 ... -
TestNG简单的学习(十二)TestNG运行
2013-12-03 09:08 51587文档来自官方地址: ... -
TestNG简单的学习(十一)TestNG学习总结
2013-12-03 09:08 14198最近一直在学习关于TestNG方面的知识,根 ... -
TestNG简单的学习(十)TestNG @Listeners 的使用
2013-12-03 09:07 8694TestNG官方网站: http://testng.or ... -
TestNG简单的学习(九)TestNG Method Interceptors 的使用
2013-12-03 09:07 2714TestNG官方网站: http://testng ... -
TestNG简单的学习(八)TestNG Annotation Transformers 的使用
2013-12-03 09:07 2810TestNG官方网站: http://testng.or ... -
TestNG简单的学习(七)TestNG编程方式运行
2013-12-02 09:22 2454TestNG官方网站: http://testng.or ... -
TestNG简单的学习(六)测试工厂注释的使用
2013-12-02 09:22 2784TestNG官方网站: http://testng.or ...
相关推荐
标题 "POI3.8组件研究(七)--基于XSSF and SAX (Event API)事件的解析" 提到了Apache POI库的一个高级话题,主要关注的是如何使用XSSF(XML Spreadsheet Formatting Streams)和SAX(Simple API for XML)的Event ...
在Excel处理方面,POI提供了一个叫做HSSF(Horrible Spreadsheet Format)的API来处理旧版的.BIFF格式(Excel 97-2007),而XSSF API则用来处理OOXML (.xlsx) 格式的Excel文件。 在 poi-examples-3.8-beta5-sources...
6. **高效率读取**:除了用户模型API,POI还提供了低级别处理,如Record和Event API,可以高效地读取文件的原始记录,适合进行深度分析或定制化操作。 7. **模板处理**:POI可以用于创建基于模板的文件生成,例如,...
5. **性能优化**:在处理大量数据时,可以使用POI的事件模型(Event API,如SXSSF)或者HSSF的RecordFactory,这些方法不需要加载整个工作簿到内存,而是按需读取,显著降低了内存占用。 6. **错误处理与兼容性**:...
- 使用POI的事件模型(EventModel API)进行低内存处理,仅在需要时读取和写入数据。 7. **文档兼容性**: - POI支持读取和写入不同版本的Office文件,但新版本的API通常提供更好的功能和性能。 总之,Apache ...
标题中的"POI3.8以及3.9的API"指的是这两个版本的API接口文档,是开发者理解和使用POI库的关键资源。API文档详尽地列出了各种类、方法和接口,使得开发者能够有效地利用POI进行文件操作。 在POI 3.8和3.9中,主要...
9. **事件模型**:POI还提供了事件模型(Event API),可以在读取文件时只处理感兴趣的单元格,从而降低内存需求。 10. **错误处理**:在编程过程中,可能会遇到各种异常,如文件格式不正确、内存不足等。理解和...
4. **事件模型**:对于大文件处理,Apache POI提供了事件模型(Event API),如SXSSF(Streaming Usermodel API)和XSSFEventBasedExcelReader,以减少内存消耗。这些API适用于处理大量数据或服务器端的批量处理场景...
4. **事件模型(Event API)**: POI还提供了一个事件模型,称为SXSSF事件模型,它在处理非常大的Excel文件时更为高效。通过监听器模式,开发者可以只处理必要的数据,而不是将整个文件加载到内存中。 5. **样式和...
4. **事件模型(Event API)**: - 对于大文件,直接加载到内存可能造成资源消耗过大。为此,POI提供了事件模型,通过`SXSSF`(Streaming Usermodel API)只在内存中保留最近使用的数据,从而减少内存使用。 5. **...
- 对于复杂操作,考虑使用Apache POI的事件模型(Event API),它只处理需要的数据,显著降低内存需求。 Apache POI 3.8版本虽然已经较旧,但在许多项目中仍然被广泛使用,因为它稳定且功能齐全。然而,为了获得...
5. **事件模型**:对于大文件,可以使用事件模型(Event API)以减少内存消耗。它不加载整个文件到内存,而是只处理必要的数据。 6. **数据公式处理**:POI支持读写Excel公式,包括计算公式的结果。 7. **流式读写...
10. **事件模型(Event API)**: 如果处理大型Excel文件,为了提高性能,可以使用事件模型,只读取需要的数据,而不是一次性加载整个文件。 11. **内存管理**: 处理大型文件时,要注意避免内存溢出。可以使用SXSSF...
4. **事件模型(EventModel)**: 为了解决大文件处理问题,POI提供了一种基于事件的模型,称为SXSSF(Streaming Usermodel API)。这种模型可以在内存有限的情况下处理大量数据,通过只保持最近使用的行在内存中。 ...