上一篇文章提过,HSSF的用户模式会导致读取海量数据时很慢,所以我们采用的是事件驱动模式。这个模式类似于xml的sax解析。需要实现一个接口,HSSFListener接口。

原理:根据excel底层存储(07以版本采用xml存储,以下版本采用二进制)标签决定事件出发点。

目标:在解析完一行(row)数据时进行触发。

优点:读取大数据时,不会导致内存溢出

缺点:用户在解析数据时比较困难。读取数据时速度不快的,因为读取数据的同时根据每个标签进行事件触发。

HSSF事件驱动读取文件的封装类解析。

主要用到两个类(一个是抽象类,一个是工具类)和一个接口:

第一个:工具类:HxlsRead.java:

package yycg.util;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List; public class HxlsRead extends HxlsAbstract{ //数据处理解析数据的接口
private HxlsOptRowsInterface hxlsOptRowsInterface;
//处理数据总数
private int optRows_sum = 0;
//处理数据成功数量
private int optRows_success = 0;
//处理数据失败数量
private int optRows_failure = 0;
//excel表格每列标题
private List<String> rowtitle ;
//失败数据
private List<List<String>> failrows;
//失败原因
private List<String> failmsgs ; //要处理数据所在的sheet索引,sheet索引从0开始
private int sheetIndex;
/**
* 导入文件的名称
* @param filename 导入文件的物理路径
* @param sheetIndex 要读取数据所在sheet序号
* @param hxlsOptRowsInterface 处理读取每一行数据的接口
* @throws IOException
* @throws FileNotFoundException
* @throws SQLException
*/
public HxlsRead(String filename,int sheetIndex,HxlsOptRowsInterface hxlsOptRowsInterface) throws IOException,
FileNotFoundException, SQLException {
super(filename);
this.sheetIndex = sheetIndex;
this.hxlsOptRowsInterface = hxlsOptRowsInterface;
this.rowtitle = new ArrayList<String>();
this.failrows = new ArrayList<List<String>>();
this.failmsgs = new ArrayList<String>();
} /**
* 对读取到一行数据进行解析
*/
@Override
public void optRows(int sheetIndex,int curRow, List<String> rowlist) throws Exception {
/*for (int i = 0 ;i< rowlist.size();i++){
System.out.print("'"+rowlist.get(i)+"',");
}
System.out.println();*/
//将rowlist的长度补齐和标题一致
int k=rowtitle.size()-rowlist.size();
for(int i=0;i<k;i++){
rowlist.add(null);
}
if(sheetIndex == this.sheetIndex){
optRows_sum++; if(curRow == 0){//记录标题
rowtitle.addAll(rowlist);
}else{
//接口返回的结果是导入数据的结果,有成功,有失败
String result = hxlsOptRowsInterface.optRows(sheetIndex, curRow, rowlist);
if(result!=null && !result.equals(hxlsOptRowsInterface.SUCCESS)){
optRows_failure++;//失败统计数加1
//失败数据列表
failrows.add(new ArrayList<String>(rowlist));
failmsgs.add(result);
}else{
optRows_success++;
}
} } } public long getOptRows_sum() {
return optRows_sum;
} public void setOptRows_sum(int optRows_sum) {
this.optRows_sum = optRows_sum;
} public long getOptRows_success() {
return optRows_success;
} public void setOptRows_success(int optRows_success) {
this.optRows_success = optRows_success;
} public long getOptRows_failure() {
return optRows_failure;
} public void setOptRows_failure(int optRows_failure) {
this.optRows_failure = optRows_failure;
} public List<String> getRowtitle() {
return rowtitle;
} public List<List<String>> getFailrows() {
return failrows;
} public List<String> getFailmsgs() {
return failmsgs;
} public void setFailmsgs(List<String> failmsgs) {
this.failmsgs = failmsgs;
} public static void main(String[] args){
HxlsRead xls2csv;
try {
//第一个参数就是导入的文件
//第二个参数就是导入文件中哪个sheet
//第三个参数导入接口的实现类对象
xls2csv = new HxlsRead("d:/test11.xls",0,new HxlsOptRowsInterfaceImpl());
xls2csv.process();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} }
}

第二个抽象类:

package yycg.util;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List; import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener;
import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
import org.apache.poi.hssf.eventusermodel.HSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener;
import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;
import org.apache.poi.hssf.model.HSSFFormulaParser;
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.LabelRecord;
import org.apache.poi.hssf.record.LabelSSTRecord;
import org.apache.poi.hssf.record.NoteRecord;
import org.apache.poi.hssf.record.NumberRecord;
import org.apache.poi.hssf.record.RKRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.SSTRecord;
import org.apache.poi.hssf.record.StringRecord;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; public abstract class HxlsAbstract implements HSSFListener {
private int minColumns;
private POIFSFileSystem fs;
private PrintStream output; private int lastRowNumber;
private int lastColumnNumber; /** Should we output the formula, or the value it has? */
private boolean outputFormulaValues = true; /** For parsing Formulas */
private SheetRecordCollectingListener workbookBuildingListener;
private HSSFWorkbook stubWorkbook; // Records we pick up as we process
private SSTRecord sstRecord;
private FormatTrackingHSSFListener formatListener; /** So we known which sheet we're on */
private int sheetIndex = -1;
private BoundSheetRecord[] orderedBSRs;
@SuppressWarnings("unchecked")
private ArrayList boundSheetRecords = new ArrayList(); // For handling formulas with string results
private int nextRow;
private int nextColumn;
private boolean outputNextStringRecord; private int curRow;
private List<String> rowlist;
@SuppressWarnings( "unused")
private String sheetName; public HxlsAbstract(POIFSFileSystem fs)
throws SQLException {
this.fs = fs;
this.output = System.out;
this.minColumns = -1;
this.curRow = 0;
this.rowlist = new ArrayList<String>();
} public HxlsAbstract(String filename) throws IOException,
FileNotFoundException, SQLException {
this(new POIFSFileSystem(new FileInputStream(filename)));
} //excel记录行操作方法,以行索引和行元素列表为参数,对一行元素进行操作,元素为String类型
// public abstract void optRows(int curRow, List<String> rowlist) throws SQLException ; //excel记录行操作方法,以sheet索引,行索引和行元素列表为参数,对sheet的一行元素进行操作,元素为String类型,rowlist存储了行数据
public abstract void optRows(int sheetIndex,int curRow, List<String> rowlist) throws Exception; /**
* 遍历 excel 文件
*/
public void process() throws IOException {
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(
this);
formatListener = new FormatTrackingHSSFListener(listener); HSSFEventFactory factory = new HSSFEventFactory();
HSSFRequest request = new HSSFRequest(); if (outputFormulaValues) {
request.addListenerForAllRecords(formatListener);
} else {
workbookBuildingListener = new SheetRecordCollectingListener(
formatListener);
request.addListenerForAllRecords(workbookBuildingListener);
} factory.processWorkbookEvents(request, fs);
} /**
* HSSFListener 监听方法,处理 Record
*/
@SuppressWarnings("unchecked")
public void processRecord(Record record) {
int thisRow = -1;
int thisColumn = -1;
String thisStr = null;
String value = null; switch (record.getSid()) {
case BoundSheetRecord.sid:
boundSheetRecords.add(record);
break;
case BOFRecord.sid:
BOFRecord br = (BOFRecord) record;
if (br.getType() == BOFRecord.TYPE_WORKSHEET) {
// Create sub workbook if required
if (workbookBuildingListener != null && stubWorkbook == null) {
stubWorkbook = workbookBuildingListener
.getStubHSSFWorkbook();
} // Works by ordering the BSRs by the location of
// their BOFRecords, and then knowing that we
// process BOFRecords in byte offset order
sheetIndex++;
if (orderedBSRs == null) {
orderedBSRs = BoundSheetRecord
.orderByBofPosition(boundSheetRecords);
}
sheetName = orderedBSRs[sheetIndex].getSheetname();
}
break; case SSTRecord.sid:
sstRecord = (SSTRecord) record;
break; case BlankRecord.sid:
BlankRecord brec = (BlankRecord) record; thisRow = brec.getRow();
thisColumn = brec.getColumn();
thisStr = "";
break;
case BoolErrRecord.sid:
BoolErrRecord berec = (BoolErrRecord) record; thisRow = berec.getRow();
thisColumn = berec.getColumn();
thisStr = "";
break; case FormulaRecord.sid:
FormulaRecord frec = (FormulaRecord) record; thisRow = frec.getRow();
thisColumn = frec.getColumn(); if (outputFormulaValues) {
if (Double.isNaN(frec.getValue())) {
// Formula result is a string
// This is stored in the next record
outputNextStringRecord = true;
nextRow = frec.getRow();
nextColumn = frec.getColumn();
} else {
thisStr = formatListener.formatNumberDateCell(frec);
}
} else {
thisStr = '"' + HSSFFormulaParser.toFormulaString(stubWorkbook,
frec.getParsedExpression()) + '"';
}
break;
case StringRecord.sid:
if (outputNextStringRecord) {
// String for formula
StringRecord srec = (StringRecord) record;
thisStr = srec.getString();
thisRow = nextRow;
thisColumn = nextColumn;
outputNextStringRecord = false;
}
break; case LabelRecord.sid:
LabelRecord lrec = (LabelRecord) record; curRow = thisRow = lrec.getRow();
thisColumn = lrec.getColumn();
value = lrec.getValue().trim();
value = value.equals("")?" ":value;
this.rowlist.add(thisColumn, value);
break;
case LabelSSTRecord.sid:
LabelSSTRecord lsrec = (LabelSSTRecord) record; curRow = thisRow = lsrec.getRow();
thisColumn = lsrec.getColumn();
if (sstRecord == null) {
rowlist.add(thisColumn, " ");
} else {
value = sstRecord
.getString(lsrec.getSSTIndex()).toString().trim();
value = value.equals("")?" ":value;
rowlist.add(thisColumn,value);
}
break;
case NoteRecord.sid:
NoteRecord nrec = (NoteRecord) record; thisRow = nrec.getRow();
thisColumn = nrec.getColumn();
// TODO: Find object to match nrec.getShapeId()
thisStr = '"' + "(TODO)" + '"';
break;
case NumberRecord.sid:
NumberRecord numrec = (NumberRecord) record; curRow = thisRow = numrec.getRow();
thisColumn = numrec.getColumn();
value = formatListener.formatNumberDateCell(numrec).trim();
value = value.equals("")?" ":value;
// Format
rowlist.add(thisColumn, value);
break;
case RKRecord.sid:
RKRecord rkrec = (RKRecord) record; thisRow = rkrec.getRow();
thisColumn = rkrec.getColumn();
thisStr = '"' + "(TODO)" + '"';
break;
default:
break;
} // 遇到新行的操作
if (thisRow != -1 && thisRow != lastRowNumber) {
lastColumnNumber = -1;
} // 空值的操作
if (record instanceof MissingCellDummyRecord) {
MissingCellDummyRecord mc = (MissingCellDummyRecord) record;
curRow = thisRow = mc.getRow();
thisColumn = mc.getColumn();
rowlist.add(thisColumn," ");
} // 如果遇到能打印的东西,在这里打印
if (thisStr != null) {
if (thisColumn > 0) {
output.print(',');
}
output.print(thisStr);
} // 更新行和列的值
if (thisRow > -1)
lastRowNumber = thisRow;
if (thisColumn > -1)
lastColumnNumber = thisColumn; // 行结束时的操作
if (record instanceof LastCellOfRowDummyRecord) {
if (minColumns > 0) {
// 列值重新置空
if (lastColumnNumber == -1) {
lastColumnNumber = 0;
}
}
// 行结束时, 调用 optRows() 方法,就是解析完每一行数据后,调用optRows进行这一行数据的处理,
lastColumnNumber = -1;
try {
optRows(sheetIndex,curRow, rowlist);
} catch (Exception e) {
e.printStackTrace();
}
rowlist.clear();
}
}
}

一个接口:把excel中数据的导出处理,就要实现这个接口

package yycg.util;

import java.util.List;

public interface HxlsOptRowsInterface {

    public static final String SUCCESS="success";
/**
* 处理excel文件每行数据方法
* @param sheetIndex 为sheet的序号
* @param curRow 为行号
* @param rowlist 行数据
* @return success:成功,否则为失败原因
* @throws Exception
*/
public String optRows(int sheetIndex,int curRow, List<String> rowlist) throws Exception; }

总结结构如下:

我们直接看HxlsRead里面的main函数里面是怎么用的(主要看注释):

    public static void main(String[] args){
HxlsRead xls2csv;
try {
//第一个参数就是导入的文件
//第二个参数就是导入文件中哪个sheet
//第三个参数导入接口的实现类对象
/**
* 这里的HxlsOptRowsInterfaceImpl()是HxlsOptRowsInterface接口的实现类。主要是 处理excel文件每行数据方法
* 就是说我们后续要把每一行数据存入到数据库的话,只要实现这个接口,然后在实现方法里面
* 实现吧数据插入到数据库就可以了。这是一个接口,当我想做别的应用的话,就可以实现这个接口,做相应的功能。
* 其他的任何结构都不用修改
*
*/
xls2csv = new HxlsRead("d:/test11.xls",0,new HxlsOptRowsInterfaceImpl());
/*
* 我们的xls2csv就是HxlsRead的类型,而HxlsRead继承了HxlsAbstract这个抽象类
* process是HxlsAbstract这个抽象类中的具体方法。这里的xls2csv.process();实际上调用的是父类
* 的process方法,我们看下父类的process方法,看到里面要调用optRows(sheetIndex,curRow, rowlist);这个抽象方法
* 在子类(本类中)已经实现了这个方法,由于多态的原因,调用的就是子类的这个方法。
*
*/
xls2csv.process();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} }

这样这个类的封装就好了。

025医疗项目-模块二:药品目录的导入导出-HSSF导入类的封装的更多相关文章

  1. 023医疗项目-模块二:药品目录的导入导出-从数据库中查出数据用XSSF导出excel并存放在虚拟目录最后下载(包括调试)

    我们要实现的效果:     进入到这个页面后,输入要查询的条件,查询出药品表的数据,然后按下导出按钮 ,就会在服务器的一个目录下生成一个药品表的excel表格.  点击"导出"之后 ...

  2. 022医疗项目-模块二:药品目录的导入导出-对XSSF导出excel类进行封装

    资源全部来源于传智播客. 好的架构师写的程序,就算给刚入门的新手看,新手一看就知道怎么去用.所以我们要对XSSF导出excel类进行封装.这是架构师的工作,但我们也要知道. 我们写一个封装类: 这个类 ...

  3. 021医疗项目-模块二:药品目录的导入导出-介绍poi类

    我们使用的是.10版本 Apache POI - the Java API for Microsoft Documents,Apache POI 是用Java编写的免费开源的跨平台的 Java API ...

  4. 027医疗项目-模块二:药品目录的导入导出-导入功能的Action的编写

    前一篇文章我们写了Service层,这篇文章我们写一下Action层. 实现的功能: 1:我们先下载模板:然后按照模板里面的规则,插入数据.比如存在d盘. 2:然后浏览找到那个文件,上传上去. 然后把 ...

  5. 026医疗项目-模块二:药品目录的导入导出-导入功能的Service的编写

    这个导入功能要实现的效果是: 思路是: 因为我们最后是在Action层中调用的HxlsRead工具,这个工具传入的就是我们要实现的上一篇文章说到的实现了HxlsOptRowsInterface接口的类 ...

  6. 024医疗项目-模块二:药品目录的导入导出-HSSF导入类的学习

    我们之前学习了怎么把数据的数据导出来保存到Excle中,这篇文章我们学习怎么Excel数据导出然后插入到数据库中. 我们先学习HSSF怎么用来导出数据. 看官方教程步骤如下: 第一步: 创建一个wor ...

  7. 044医疗项目-模块四:采购单模块—采购单保存(Dao,Service,Action三层)

    我们上上一篇文章(042医疗项目-模块四:采购单模块-采购单明细添加查询,并且把数据添加到数据库中)做的工作是把数据插入到了数据库,我们这篇文章做的是042医疗项目-模块四:采购单模块-采购单明细添加 ...

  8. NPOI导入导出EXCEL通用类,供参考,可直接使用在WinForm项目中

    以下是NPOI导入导出EXCEL通用类,是在别人的代码上进行优化的,兼容xls与xlsx文件格式,供参考,可直接使用在WinForm项目中,由于XSSFWorkbook类型的Write方法限制,Wri ...

  9. 035医疗项目-模块三:药品供应商目录模块——供货商药品目录(批量)添加药品的功能---------Service

    这篇文章我们重点介绍Service层.因为Dao层就是用Gysypml逆向生成的Mapper就可以了.所以这里重点讲解Service层. 业务逻辑如下: 1:我们从前端页面传入有两个值:1:userg ...

随机推荐

  1. R语言学习笔记:简单的回归分析

    fitbit <- read.csv("fitbit.csv") date     cal   step  dist floor sit inactive walk run2 ...

  2. yii url美化 urlManager组件

    yii的官方文档对此的解释如下: urlSuffix  此规则使用的url后缀,默认使用CurlManger::urlSuffix,值为null.例如可以将此设置为.html,让url看起来“像”是一 ...

  3. 基础学习day02--标识符、关键字、数据类型与运算符

    一.标识符和关键字   关键字: 就是被java语言赋予了特殊含义的单词. 特点就是所有的关键字都是小写.   标识符: 就是给包.类.接口.方法.变量名起的名字. 规则:1.以数字.字母._以及$符 ...

  4. ARC-数据类型需要释放的情况

    // Foundation :  OC// Core Foundation : C语言// Foundation和Core Foundation框架的数据类型可以互相转换的 //NSString *s ...

  5. Undefined symbols for architecture i386:和"_OBJC_CLASS_$_xx", referenced from:问题解决方法

    多个人共同操作同一个项目或拷贝项目时,经常会出现类似这样的问题: Undefined symbols for architecture i386: "_OBJC_CLASS_$_xx文件名& ...

  6. dd 生成指定大小文件

    d命令可以轻易实现创建指定大小的文件,如 dd if=/dev/zero of=test bs=1M count=1000 会生成一个1000M的test文件,文件内容为全0(因从/dev/zero中 ...

  7. Effective Java 05 Avoid creating unnecessary objects

    String s = new String("stringette"); // Don't do this. This will create an object each tim ...

  8. Effective Java 60 Favor the use of standard exceptions

    Benefits to reuse preexisting exceptions It makes your API easier to learn and use. Programs using y ...

  9. C#获取HTML文件指定DIV内容

    最近自己找了一个开源的博客网站,放到阿里云上,方便自己发布博客. 我一般把文章发布到博客园和QQ空间,家了这个网站后又要多发布一次,为了省事就做了一个从博客园读取文章的功能: 输入链接URL地址点击提 ...

  10. 【DPDK】虚拟机开发环境配置

    DPDK介绍见:www.dpdk.org 本文介绍的步骤基本适用于dpdk 1.7.0 - dpdk 2.0.0 各版本.只是setup.sh显示的菜单有一些小的不同:同样的,也适用于ubuntu更高 ...