POI实现大数据的导入
之前介绍过通过POI实现数据的导出以及百万数据的导出,今天介绍一般数据以及大数据集的数据导入。之前介绍过POI操作Excel2007的三种模式:
用户模式:有许多分装好的方法操作简单事件模式:基于SAX方式解析XML,他是一个接口,是一种XML解析的替代方法,不同于DOM解析XML文档时把所有数据内容一次性加载到内存,他是逐行扫描SXSSF对象:生成海量Excel数据文件
POI基于用户模式的数据导出
主要步骤:根据上传信息创建Workbok根据Workbook创建Sheet读取Sheet行中数据
@ApiOperation(value="导入数据")
@RequestMapping(value="/importpoi",method=RequestMethod.POST)
@ResponseBody
publicCommonResultimportExcelPOI(@RequestParam(name="file")MultipartFileimportfile)throwsException{
//根据上传信息创建workbool
Workbooksheets=WorkbookFactory.create(importfile.getInputStream());
//创建一个sheet
Sheetsheet=sheets.getSheetAt(0);
//从第二行获取数据
List<MesAdmin>mesAdmins=newArrayList<>();
//从第二行读取数据
for(intrown=1;rown<sheet.getLastRowNum();rown++){
Rowrow=sheet.getRow(rown);
MesAdminmesAdmin=newMesAdmin();
for(intcelln=0;celln<row.getLastCellNum();celln++){
//此处为数据每行数据以及对每行数据进行操作
}
}
returnCommonResult.success(ResultCode.SUCCESS);
}
使用POI的SAX(事件)模式读取百万数据
POI在对Excel的XML解析以及做了一些封装,我们只有实现这些封才可以安装SAX方式进行读取Excel,主要就是要实现XSSFSheetXMLHandler.SheetContentsHandler接口,给接口有三个方式需要我们去实现:
方法作用public void startRow(int i)开始读取行public void endRow(int i)结束读取行public void cell(String s, String s1, XSSFComment xssfComment)读取行中单元
需求分析
使用POI的SAX模式解析EXCEl文件
解决方案
使用SAX模式,逐行扫描文件,一边扫描一遍解析。不需要将数据存储到内存,对于大型文档解析具有很大优势。
步骤分析
设置POI的时间模式
1.根据Excel获取文件流
2.根据文件流创建OPCPackage
3.创建XSSFReader对象
SAX解析
1.自定义Sheet处理器
2.创建Sax的XmlReader
3.设置Sheet事件处理器
4.逐行读取
原理分析
Excel2007的本质就是一种特殊的XML存储数据,这样就可以使用基于SXA的方式去解析XML完成对Excel的读取。SAX提供一种从XML文档读取数据的机制,逐行扫描文档,一边扫描一边解析,解析原理如图:


代码实现
自定义实现XSSFSheetXMLHandler.SheetContentsHandler处理器
packagecom.macro.mall.tiny.config;
importorg.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
importorg.apache.poi.xssf.usermodel.XSSFComment;
importjava.util.ArrayList;
importjava.util.List;
//自定义Sheet给予Sax解析处理器
publicclassMesSheetHandlerimplementsXSSFSheetXMLHandler.SheetContentsHandler{
//行信息
privateList<String>lRows=newArrayList<String>();//处理一行信息
@Override
publicvoidstartRow(inti){
if(i>0){
lRows.clear();
}
}
/**
*解析行
*@parami
*/
@Override
publicvoidendRow(inti){
//可以每行都对数据进行插入操作,也可以使用监听进行数据操作
System.out.println("i:"+lRows.get(0));
}
/**
*逐单元读取数据
*@params
*@params1
*@paramxssfComment
*/
@Override
publicvoidcell(Strings,Strings1,XSSFCommentxssfComment){
if(lRows!=null){
lRows.add(s1);
}else{
lRows.add("");
}
}
}
在Controller层实现解析
@ApiOperation(value="批量导入用户数据")
@RequestMapping(value="/importpoi",method=RequestMethod.POST)
@ResponseBody
publicCommonResultimportExcelpoiSax(@RequestParam(name="file")MultipartFilemultipartFile,HttpServletRequestrequest)throwsException{
//Stringfile="C:/Users/180454/Downloads/1.xlsx";
//根据Eccel获取OPCPackage对象
OPCPackagepkg=OPCPackage.open(multipartFile.getInputStream());
//
try{
//创建XSSFReader
XSSFReaderxssfReader=newXSSFReader(pkg);
//获取SharedStringTable对象
SharedStringsTablesharedStringsTable=xssfReader.getSharedStringsTable();
//获取StylesTable对象
StylesTablestyles=xssfReader.getStylesTable();
XMLReaderxmlReader=XMLReaderFactory.createXMLReader();
MesSheetHandlermesSheetHandler=newMesSheetHandler();
xmlReader.setContentHandler(newXSSFSheetXMLHandler(styles,sharedStringsTable,mesSheetHandler,false));
XSSFReader.SheetIteratorsheets=(XSSFReader.SheetIterator)xssfReader.getSheetsData();
//每一个Sheet
while(sheets.hasNext()){
InputStreamsheetstream=sheets.next();
InputSourcesheetSource=newInputSource(sheetstream);
try{
xmlReader.parse(sheetSource);
LOGGER.info("row:"+"结束");
}finally{
sheetstream.close();
}
}
}finally{
pkg.close();
}
returnCommonResult.success(ResultCode.SUCCESS);
}
总结:
通过简单地介绍Excel读取数据的两种模式,可以发现在用户模式下Excel读取实现简单但是内存占用量大,不理想,而事件模式操作比较繁琐,但是可以读取大文件的Excel。