本文主要记录最近的工作内容,使用java实现对Excel(03,07)的上传、解析、验证和入库(PostgreSQL)。
一。上传
实际就是实现文件上传至服务器即可,但是方法有很多,首先要考虑采用何种方法实现上传:
1.参考文章:
Java开发过程中文件上传的各种方式全面总结 http://javacrazyer.iteye.com/blog/707705
主要有以下几种方法:
JSP+Servlet(或纯JSP);Struts2;Struts;FTP;ExtJs;Flex;
2.我采用的是jsp+Servlet的方式来实现的。需要先从apache官网下载fileupload.jar。
UploadFileServlet.java的主要代码:
testfileupload.jsp的主要代码:
3.需要注意的几个问题
(1)上传文件的大小限制
设置 sfu.setFileSizeMax(1024*1024*10000);单位byte.表示近10G。
测试上传1.5G的文件没问题,2.9G以上的文件上传失败,无错误提示,而是“无法显示该页面”的错误:
所以目前不清楚到底支持多大的文件上传。
二。解析
1.java解析excel通常有两种方法:(1)jxl(2)poi.
至于选用哪种那做得看具体的需求,我这次主要是要支持03,07的excel,目前jxl更新慢,尚不支持07,所以只能选用poi;本次只涉及到excel的读操作,没有写操作,jxl的写快于poi,但jxl的读慢于poi.
综合下来,选用poi。这个poi具体是啥意思我不太清楚,但不是常说的感兴趣点(point of interest)哈.
2.是否支持大文件解析
excel03最多只能有65536条记录,65536行*256列;excel07:1048576行*16384列。
excel07文件超过65536条记录,另存为xls时会报错:
所以要支持大文件,必须得用excel07格式来操作。
需要考虑这点,因为这决定了是用DOM做,还是用SAX。
就1和2来看,java解析excel比起.net解析excel是麻烦了很多很多啊,.net解析excel主要有三种方法:com组件;oledb;openxml。其中使用oledb最常用也最简单。
3.jar包下载
jxl;http://www.andykhan.com/jexcelapi/download.html,最新版本为JExcelApiv2.6.12
poi:http://poi.apache.org/download.html#POI-3.9,最新版本为poi-bin-3.9-20121203.zip
4.poi+SAX,支持excel07大文件解析(EventUserModel)
这种方式应该是最高级别的,能满足大数据量需求,也不会造成oom错误的。我这次需要采用的就是这种实现方式。
主要定义了三个类来实现:
(1)Excel2003Reader.java,操作03Excel。
package com.cbe.excel;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
importorg.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener;
importorg.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;
importorg.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener;
importorg.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;
importorg.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.NumberRecord;
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 class Excel2003Reader implements HSSFListener {
private int minColumns = -1;
private POIFSFileSystem fs;
private int lastRowNumber;
private int lastColumnNumber;
private boolean outputFormulaValues = true;
private SheetRecordCollectingListenerworkbookBuildingListener;
//excel2003工作薄
private HSSFWorkbook stubWorkbook;
// Records we pick up as we process
private SSTRecord sstRecord;
private FormatTrackingHSSFListenerformatListener;
//表索引
private int sheetIndex = -1;
private BoundSheetRecord[] orderedBSRs;
//@SuppressWarnings("unchecked")
@SuppressWarnings("rawtypes")
private ArrayList boundSheetRecords = newArrayList();
// For handling formulas with stringresults
private int nextRow;
private int nextColumn;
private boolean outputNextStringRecord;
//当前行
//private int curRow = 0;
//存储行记录的容器
privateList<String> rowlist = newArrayList<String>();
privateList<List<String>>exceldata=newArrayList<List<String>>();
@SuppressWarnings( "unused")
private String sheetName;
publicList<List<String>>getExcelData(){
return exceldata;
}
public void process(String fileName) throwsIOException {
this.fs = newPOIFSFileSystem(new FileInputStream(fileName));
MissingRecordAwareHSSFListenerlistener = new MissingRecordAwareHSSFListener(
this);
formatListener = newFormatTrackingHSSFListener(listener);
HSSFEventFactory factory = newHSSFEventFactory();
HSSFRequest request = newHSSFRequest();
if (outputFormulaValues){
request.addListenerForAllRecords(formatListener);
} else {
workbookBuildingListener= new SheetRecordCollectingListener(
formatListener);
request.addListenerForAllRecords(workbookBuildingListener);
}
factory.processWorkbookEvents(request,fs);
}
@SuppressWarnings("unchecked")
public void processRecord(Record record) {
//List<String> rowlist = newArrayList<String>();
int thisRow = -1;
int thisColumn = -1;
String thisStr = null;
String value = null;
switch (record.getSid()){
caseBoundSheetRecord.sid:
boundSheetRecords.add(record);
break;
caseBOFRecord.sid:
BOFRecordbr = (BOFRecord) record;
if(br.getType() == BOFRecord.TYPE_WORKSHEET) {
//如果有需要,则建立子工作薄
if(workbookBuildingListener != null&& stubWorkbook == null) {
stubWorkbook= workbookBuildingListener
.getStubHSSFWorkbook();
}
sheetIndex++;
if(orderedBSRs == null) {
orderedBSRs= BoundSheetRecord
.orderByBofPosition(boundSheetRecords);
}
sheetName= orderedBSRs[sheetIndex].getSheetname();
}
break;
caseSSTRecord.sid:
sstRecord= (SSTRecord) record;
break;
caseBlankRecord.sid:
BlankRecordbrec = (BlankRecord) record;
thisRow= brec.getRow();
thisColumn= brec.getColumn();
thisStr= "";
rowlist.add(thisColumn,thisStr);
break;
caseBoolErrRecord.sid: //单元格为布尔类型
BoolErrRecordberec = (BoolErrRecord) record;
thisRow= berec.getRow();
thisColumn= berec.getColumn();
thisStr= berec.getBooleanValue()+"";