首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

POI3.8组件研究(4)-Event API (HSSF Only)事件的解析

2012-06-26 
POI3.8组件研究(四)--Event API (HSSF Only)事件的解析??? 通过eventusermodel读取文件    通过eventuserm

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;    @Overridepublic 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.FilesystemPOIFSFileSystem 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 {SheetRecordCollectingListenerworkbookBuildingListener = 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文件如下:

?

?

?

热点排行