博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POI读写大数据量excel,解决超过几万行而导致内存溢出的问题
阅读量:4090 次
发布时间:2019-05-25

本文共 29643 字,大约阅读时间需要 98 分钟。

1. Excel2003与Excel2007

两个版本的最大行数和列数不同,2003版最大行数是65536行,最大列数是256列,2007版及以后的版本最大行数是1048576行,最大列数是16384列。

excel2003是以二进制的方式存储,这种格式不易被其他软件读取使用;而excel2007采用了基于XML的ooxml开放文档标准,ooxml使用XML和ZIP技术结合进行文件存储,XML是一个基于文本的格式,而且ZIP容器支持内容的压缩,所以其一大优势是可以大大减小文件的尺寸。

2. 大批量数据读写

2.1 大批量数据写入

对于大数据的Xlsx文件的写入,POI3.8提供了SXSSFSXSSFWorkbook类,采用缓存方式进行大批量写文件。

详情可以查看poi官网示例: 或 

2.2 大批量数据读取

POI读取Excel有两种模式,一种是用户模式,一种是SAX事件驱动模式,将xlsx格式的文档转换成CSV格式后进行读取。用户模式API接口丰富,使用POI的API可以很容易读取Excel,但用户模式消耗的内存很大,当遇到很大sheet、大数据网格,假空行、公式等问题时,很容易导致内存溢出。POI官方推荐解决内存溢出的方式使用CVS格式解析,即SAX事件驱动模式。下面主要是讲解如何读取大批量数据:

2.2.1 pom.xml所需jar包

1 
3
4.0.0
4
POIExcel
5
POIExcel
6
war
7
1.0-SNAPSHOT
8
POIExcel Maven Webapp
9
http://maven.apache.org
10
11
12
junit
13
junit
14
3.8.1
15
test
16
17 18
19
org.apache.poi
20
poi
21
3.17
22
23 24
25
org.apache.poi
26
poi-ooxml
27
3.17
28
29 30
31
org.apache.poi
32
poi-ooxml-schemas
33
3.17
34
35 36
37
com.syncthemall
38
boilerpipe
39
1.2.1
40
41 42
43
xerces
44
xercesImpl
45
2.11.0
46
47 48
49
xml-apis
50
xml-apis
51
1.4.01
52
53 54
55
org.apache.xmlbeans
56
xmlbeans
57
2.6.0
58
59 60
61
sax
62
sax
63
2.0.1
64
65 66
67
org.apache.commons
68
commons-lang3
69
3.7
70
71 72
73
74
POIExcel
75
76

2.2.2 POI以SAX解析excel2007文件

解决思路:通过继承DefaultHandler类,重写process(),startElement(),characters(),endElement()这四个方法。process()方式主要是遍历所有的sheet,并依次调用startElement()、characters()方法、endElement()这三个方法。startElement()用于设定单元格的数字类型(如日期、数字、字符串等等)。characters()用于获取该单元格对应的索引值或是内容值(如果单元格类型是字符串、INLINESTR、数字、日期则获取的是索引值;其他如布尔值、错误、公式则获取的是内容值)。endElement()根据startElement()的单元格数字类型和characters()的索引值或内容值,最终得出单元格的内容值,并打印出来。

1 package org.poi;  2   3 import org.apache.poi.openxml4j.opc.OPCPackage;  4 import org.apache.poi.ss.usermodel.BuiltinFormats;  5 import org.apache.poi.ss.usermodel.DataFormatter;  6 import org.apache.poi.xssf.eventusermodel.XSSFReader;  7 import org.apache.poi.xssf.model.SharedStringsTable;  8 import org.apache.poi.xssf.model.StylesTable;  9 import org.apache.poi.xssf.usermodel.XSSFCellStyle; 10 import org.apache.poi.xssf.usermodel.XSSFRichTextString; 11 import org.xml.sax.Attributes; 12 import org.xml.sax.InputSource; 13 import org.xml.sax.SAXException; 14 import org.xml.sax.XMLReader; 15 import org.xml.sax.helpers.DefaultHandler; 16 import org.xml.sax.helpers.XMLReaderFactory; 17  18 import java.io.InputStream; 19 import java.util.ArrayList; 20 import java.util.List; 21  22 /** 23  * @author y 24  * @create 2018-01-18 14:28 25  * @desc POI读取excel有两种模式,一种是用户模式,一种是事件驱动模式 26  * 采用SAX事件驱动模式解决XLSX文件,可以有效解决用户模式内存溢出的问题, 27  * 该模式是POI官方推荐的读取大数据的模式, 28  * 在用户模式下,数据量较大,Sheet较多,或者是有很多无用的空行的情况下,容易出现内存溢出 29  * 

30 * 用于解决.xlsx2007版本大数据量问题 31 **/ 32 public class ExcelXlsxReader extends DefaultHandler { 33 34 /** 35 * 单元格中的数据可能的数据类型 36 */ 37 enum CellDataType { 38 BOOL, ERROR, FORMULA, INLINESTR, SSTINDEX, NUMBER, DATE, NULL 39 } 40 41 /** 42 * 共享字符串表 43 */ 44 private SharedStringsTable sst; 45 46 /** 47 * 上一次的索引值 48 */ 49 private String lastIndex; 50 51 /** 52 * 文件的绝对路径 53 */ 54 private String filePath = ""; 55 56 /** 57 * 工作表索引 58 */ 59 private int sheetIndex = 0; 60 61 /** 62 * sheet名 63 */ 64 private String sheetName = ""; 65 66 /** 67 * 总行数 68 */ 69 private int totalRows=0; 70 71 /** 72 * 一行内cell集合 73 */ 74 private List

cellList = new ArrayList
(); 75 76 /** 77 * 判断整行是否为空行的标记 78 */ 79 private boolean flag = false; 80 81 /** 82 * 当前行 83 */ 84 private int curRow = 1; 85 86 /** 87 * 当前列 88 */ 89 private int curCol = 0; 90 91 /** 92 * T元素标识 93 */ 94 private boolean isTElement; 95 96 /** 97 * 异常信息,如果为空则表示没有异常 98 */ 99 private String exceptionMessage;100 101 /**102 * 单元格数据类型,默认为字符串类型103 */104 private CellDataType nextDataType = CellDataType.SSTINDEX;105 106 private final DataFormatter formatter = new DataFormatter();107 108 /**109 * 单元格日期格式的索引110 */111 private short formatIndex;112 113 /**114 * 日期格式字符串115 */116 private String formatString;117 118 //定义前一个元素和当前元素的位置,用来计算其中空的单元格数量,如A6和A8等119 private String preRef = null, ref = null;120 121 //定义该文档一行最大的单元格数,用来补全一行最后可能缺失的单元格122 private String maxRef = null;123 124 /**125 * 单元格126 */127 private StylesTable stylesTable;128 129 /**130 * 遍历工作簿中所有的电子表格131 * 并缓存在mySheetList中132 *133 * @param filename134 * @throws Exception135 */136 public int process(String filename) throws Exception {137 filePath = filename;138 OPCPackage pkg = OPCPackage.open(filename);139 XSSFReader xssfReader = new XSSFReader(pkg);140 stylesTable = xssfReader.getStylesTable();141 SharedStringsTable sst = xssfReader.getSharedStringsTable();142 XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");143 this.sst = sst;144 parser.setContentHandler(this);145 XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) xssfReader.getSheetsData();146 while (sheets.hasNext()) { //遍历sheet147 curRow = 1; //标记初始行为第一行148 sheetIndex++;149 InputStream sheet = sheets.next(); //sheets.next()和sheets.getSheetName()不能换位置,否则sheetName报错150 sheetName = sheets.getSheetName();151 InputSource sheetSource = new InputSource(sheet);152 parser.parse(sheetSource); //解析excel的每条记录,在这个过程中startElement()、characters()、endElement()这三个函数会依次执行153 sheet.close();154 }155 return totalRows; //返回该excel文件的总行数,不包括首列和空行156 }157 158 /**159 * 第一个执行160 *161 * @param uri162 * @param localName163 * @param name164 * @param attributes165 * @throws SAXException166 */167 @Override168 public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {169 //c => 单元格170 if ("c".equals(name)) {171 //前一个单元格的位置172 if (preRef == null) {173 preRef = attributes.getValue("r");174 } else {175 preRef = ref;176 }177 178 //当前单元格的位置179 ref = attributes.getValue("r");180 //设定单元格类型181 this.setNextDataType(attributes);182 }183 184 //当元素为t时185 if ("t".equals(name)) {186 isTElement = true;187 } else {188 isTElement = false;189 }190 191 //置空192 lastIndex = "";193 }194 195 /**196 * 第二个执行197 * 得到单元格对应的索引值或是内容值198 * 如果单元格类型是字符串、INLINESTR、数字、日期,lastIndex则是索引值199 * 如果单元格类型是布尔值、错误、公式,lastIndex则是内容值200 * @param ch201 * @param start202 * @param length203 * @throws SAXException204 */205 @Override206 public void characters(char[] ch, int start, int length) throws SAXException {207 lastIndex += new String(ch, start, length);208 }209 210 /**211 * 第三个执行212 *213 * @param uri214 * @param localName215 * @param name216 * @throws SAXException217 */218 @Override219 public void endElement(String uri, String localName, String name) throws SAXException {220 221 //t元素也包含字符串222 if (isTElement) {
//这个程序没经过223 //将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符224 String value = lastIndex.trim();225 cellList.add(curCol, value);226 curCol++;227 isTElement = false;228 //如果里面某个单元格含有值,则标识该行不为空行229 if (value != null && !"".equals(value)) {230 flag = true;231 }232 } else if ("v".equals(name)) {233 //v => 单元格的值,如果单元格是字符串,则v标签的值为该字符串在SST中的索引234 String value = this.getDataValue(lastIndex.trim(), "");//根据索引值获取对应的单元格值235 //补全单元格之间的空单元格236 if (!ref.equals(preRef)) {237 int len = countNullCell(ref, preRef);238 for (int i = 0; i < len; i++) {239 cellList.add(curCol, "");240 curCol++;241 }242 }243 cellList.add(curCol, value);244 curCol++;245 //如果里面某个单元格含有值,则标识该行不为空行246 if (value != null && !"".equals(value)) {247 flag = true;248 }249 } else {250 //如果标签名称为row,这说明已到行尾,调用optRows()方法251 if ("row".equals(name)) {252 //默认第一行为表头,以该行单元格数目为最大数目253 if (curRow == 1) {254 maxRef = ref;255 }256 //补全一行尾部可能缺失的单元格257 if (maxRef != null) {258 int len = countNullCell(maxRef, ref);259 for (int i = 0; i <= len; i++) {260 cellList.add(curCol, "");261 curCol++;262 }263 }264 265 if (flag&&curRow!=1){ //该行不为空行且该行不是第一行,则发送(第一行为列名,不需要)266 ExcelReaderUtil.sendRows(filePath, sheetName, sheetIndex, curRow, cellList);267 totalRows++;268 }269 270 cellList.clear();271 curRow++;272 curCol = 0;273 preRef = null;274 ref = null;275 flag=false;276 }277 }278 }279 280 /**281 * 处理数据类型282 *283 * @param attributes284 */285 public void setNextDataType(Attributes attributes) {286 nextDataType = CellDataType.NUMBER; //cellType为空,则表示该单元格类型为数字287 formatIndex = -1;288 formatString = null;289 String cellType = attributes.getValue("t"); //单元格类型290 String cellStyleStr = attributes.getValue("s"); //291 String columnData = attributes.getValue("r"); //获取单元格的位置,如A1,B1292 293 if ("b".equals(cellType)) { //处理布尔值294 nextDataType = CellDataType.BOOL;295 } else if ("e".equals(cellType)) { //处理错误296 nextDataType = CellDataType.ERROR;297 } else if ("inlineStr".equals(cellType)) {298 nextDataType = CellDataType.INLINESTR;299 } else if ("s".equals(cellType)) { //处理字符串300 nextDataType = CellDataType.SSTINDEX;301 } else if ("str".equals(cellType)) {302 nextDataType = CellDataType.FORMULA;303 }304 305 if (cellStyleStr != null) { //处理日期306 int styleIndex = Integer.parseInt(cellStyleStr);307 XSSFCellStyle style = stylesTable.getStyleAt(styleIndex);308 formatIndex = style.getDataFormat();309 formatString = style.getDataFormatString();310 311 if (formatString.contains("m/d/yy")) {312 nextDataType = CellDataType.DATE;313 formatString = "yyyy-MM-dd hh:mm:ss";314 }315 316 if (formatString == null) {317 nextDataType = CellDataType.NULL;318 formatString = BuiltinFormats.getBuiltinFormat(formatIndex);319 }320 }321 }322 323 /**324 * 对解析出来的数据进行类型处理325 * @param value 单元格的值,326 * value代表解析:BOOL的为0或1, ERROR的为内容值,FORMULA的为内容值,INLINESTR的为索引值需转换为内容值,327 * SSTINDEX的为索引值需转换为内容值, NUMBER为内容值,DATE为内容值328 * @param thisStr 一个空字符串329 * @return330 */331 @SuppressWarnings("deprecation")332 public String getDataValue(String value, String thisStr) {333 switch (nextDataType) {334 // 这几个的顺序不能随便交换,交换了很可能会导致数据错误335 case BOOL: //布尔值336 char first = value.charAt(0);337 thisStr = first == '0' ? "FALSE" : "TRUE";338 break;339 case ERROR: //错误340 thisStr = "\"ERROR:" + value.toString() + '"';341 break;342 case FORMULA: //公式343 thisStr = '"' + value.toString() + '"';344 break;345 case INLINESTR:346 XSSFRichTextString rtsi = new XSSFRichTextString(value.toString());347 thisStr = rtsi.toString();348 rtsi = null;349 break;350 case SSTINDEX: //字符串351 String sstIndex = value.toString();352 try {353 int idx = Integer.parseInt(sstIndex);354 XSSFRichTextString rtss = new XSSFRichTextString(sst.getEntryAt(idx));//根据idx索引值获取内容值355 thisStr = rtss.toString();356 rtss = null;357 } catch (NumberFormatException ex) {358 thisStr = value.toString();359 }360 break;361 case NUMBER: //数字362 if (formatString != null) {363 thisStr = formatter.formatRawCellContents(Double.parseDouble(value), formatIndex, formatString).trim();364 } else {365 thisStr = value;366 }367 thisStr = thisStr.replace("_", "").trim();368 break;369 case DATE: //日期370 thisStr = formatter.formatRawCellContents(Double.parseDouble(value), formatIndex, formatString);371 // 对日期字符串作特殊处理,去掉T372 thisStr = thisStr.replace("T", " ");373 break;374 default:375 thisStr = " ";376 break;377 }378 return thisStr;379 }380 381 public int countNullCell(String ref, String preRef) {382 //excel2007最大行数是1048576,最大列数是16384,最后一列列名是XFD383 String xfd = ref.replaceAll("\\d+", "");384 String xfd_1 = preRef.replaceAll("\\d+", "");385 386 xfd = fillChar(xfd, 3, '@', true);387 xfd_1 = fillChar(xfd_1, 3, '@', true);388 389 char[] letter = xfd.toCharArray();390 char[] letter_1 = xfd_1.toCharArray();391 int res = (letter[0] - letter_1[0]) * 26 * 26 + (letter[1] - letter_1[1]) * 26 + (letter[2] - letter_1[2]);392 return res - 1;393 }394 395 public String fillChar(String str, int len, char let, boolean isPre) {396 int len_1 = str.length();397 if (len_1 < len) {398 if (isPre) {399 for (int i = 0; i < (len - len_1); i++) {400 str = let + str;401 }402 } else {403 for (int i = 0; i < (len - len_1); i++) {404 str = str + let;405 }406 }407 }408 return str;409 }410 411 /**412 * @return the exceptionMessage413 */414 public String getExceptionMessage() {415 return exceptionMessage;416 }417 }

2.2.3 POI通过继承HSSFListener类来解决Excel2003文件

 解决思路:重写process(),processRecord()两个方法,其中processRecord是核心方法,用于处理sheetName和各种单元格数字类型。

1 package org.poi;  2   3 import org.apache.poi.hssf.eventusermodel.*;  4 import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;  5 import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;  6 import org.apache.poi.hssf.model.HSSFFormulaParser;  7 import org.apache.poi.hssf.record.*;  8 import org.apache.poi.hssf.usermodel.HSSFDataFormatter;  9 import org.apache.poi.hssf.usermodel.HSSFWorkbook; 10 import org.apache.poi.poifs.filesystem.POIFSFileSystem; 11  12 import java.io.FileInputStream; 13 import java.util.ArrayList; 14 import java.util.List; 15  16 /** 17  * @author y 18  * @create 2018-01-19 14:18 19  * @desc 用于解决.xls2003版本大数据量问题 20  **/ 21 public class ExcelXlsReader implements HSSFListener { 22  23     private int minColums = -1; 24  25     private POIFSFileSystem fs; 26  27     /** 28      * 总行数 29      */ 30     private int totalRows=0; 31  32     /** 33      * 上一行row的序号 34      */ 35     private int lastRowNumber; 36  37     /** 38      * 上一单元格的序号 39      */ 40     private int lastColumnNumber; 41  42     /** 43      * 是否输出formula,还是它对应的值 44      */ 45     private boolean outputFormulaValues = true; 46  47     /** 48      * 用于转换formulas 49      */ 50     private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener; 51  52     //excel2003工作簿 53     private HSSFWorkbook stubWorkbook; 54  55     private SSTRecord sstRecord; 56  57     private FormatTrackingHSSFListener formatListener; 58  59     private final HSSFDataFormatter formatter = new HSSFDataFormatter(); 60  61     /** 62      * 文件的绝对路径 63      */ 64     private String filePath = ""; 65  66     //表索引 67     private int sheetIndex = 0; 68  69     private BoundSheetRecord[] orderedBSRs; 70  71     @SuppressWarnings("unchecked") 72     private ArrayList boundSheetRecords = new ArrayList(); 73  74     private int nextRow; 75  76     private int nextColumn; 77  78     private boolean outputNextStringRecord; 79  80     //当前行 81     private int curRow = 0; 82  83     //存储一行记录所有单元格的容器 84     private List
cellList = new ArrayList
(); 85 86 /** 87 * 判断整行是否为空行的标记 88 */ 89 private boolean flag = false; 90 91 @SuppressWarnings("unused") 92 private String sheetName; 93 94 /** 95 * 遍历excel下所有的sheet 96 * 97 * @param fileName 98 * @throws Exception 99 */100 public int process(String fileName) throws Exception {101 filePath = fileName;102 this.fs = new POIFSFileSystem(new FileInputStream(fileName));103 MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);104 formatListener = new FormatTrackingHSSFListener(listener);105 HSSFEventFactory factory = new HSSFEventFactory();106 HSSFRequest request = new HSSFRequest();107 if (outputFormulaValues) {108 request.addListenerForAllRecords(formatListener);109 } else {110 workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener);111 request.addListenerForAllRecords(workbookBuildingListener);112 }113 factory.processWorkbookEvents(request, fs);114 115 return totalRows; //返回该excel文件的总行数,不包括首列和空行116 }117 118 /**119 * HSSFListener 监听方法,处理Record120 * 处理每个单元格121 * @param record122 */123 @SuppressWarnings("unchecked")124 public void processRecord(Record record) {125 int thisRow = -1;126 int thisColumn = -1;127 String thisStr = null;128 String value = null;129 switch (record.getSid()) {130 case BoundSheetRecord.sid:131 boundSheetRecords.add(record);132 break;133 case BOFRecord.sid: //开始处理每个sheet134 BOFRecord br = (BOFRecord) record;135 if (br.getType() == BOFRecord.TYPE_WORKSHEET) {136 //如果有需要,则建立子工作簿137 if (workbookBuildingListener != null && stubWorkbook == null) {138 stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook();139 }140 141 if (orderedBSRs == null) {142 orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords);143 }144 sheetName = orderedBSRs[sheetIndex].getSheetname();145 sheetIndex++;146 }147 break;148 case SSTRecord.sid:149 sstRecord = (SSTRecord) record;150 break;151 case BlankRecord.sid: //单元格为空白152 BlankRecord brec = (BlankRecord) record;153 thisRow = brec.getRow();154 thisColumn = brec.getColumn();155 thisStr = "";156 cellList.add(thisColumn, thisStr);157 break;158 case BoolErrRecord.sid: //单元格为布尔类型159 BoolErrRecord berec = (BoolErrRecord) record;160 thisRow = berec.getRow();161 thisColumn = berec.getColumn();162 thisStr = berec.getBooleanValue() + "";163 cellList.add(thisColumn, thisStr);164 checkRowIsNull(thisStr); //如果里面某个单元格含有值,则标识该行不为空行165 break;166 case FormulaRecord.sid://单元格为公式类型167 FormulaRecord frec = (FormulaRecord) record;168 thisRow = frec.getRow();169 thisColumn = frec.getColumn();170 if (outputFormulaValues) {171 if (Double.isNaN(frec.getValue())) {172 outputNextStringRecord = true;173 nextRow = frec.getRow();174 nextColumn = frec.getColumn();175 } else {176 thisStr = '"' + HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()) + '"';177 }178 } else {179 thisStr = '"' + HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()) + '"';180 }181 cellList.add(thisColumn, thisStr);182 checkRowIsNull(thisStr); //如果里面某个单元格含有值,则标识该行不为空行183 break;184 case StringRecord.sid: //单元格中公式的字符串185 if (outputNextStringRecord) {186 StringRecord srec = (StringRecord) record;187 thisStr = srec.getString();188 thisRow = nextRow;189 thisColumn = nextColumn;190 outputNextStringRecord = false;191 }192 break;193 case LabelRecord.sid:194 LabelRecord lrec = (LabelRecord) record;195 curRow = thisRow = lrec.getRow();196 thisColumn = lrec.getColumn();197 value = lrec.getValue().trim();198 value = value.equals("") ? "" : value;199 cellList.add(thisColumn, value);200 checkRowIsNull(value); //如果里面某个单元格含有值,则标识该行不为空行201 break;202 case LabelSSTRecord.sid: //单元格为字符串类型203 LabelSSTRecord lsrec = (LabelSSTRecord) record;204 curRow = thisRow = lsrec.getRow();205 thisColumn = lsrec.getColumn();206 if (sstRecord == null) {207 cellList.add(thisColumn, "");208 } else {209 value = sstRecord.getString(lsrec.getSSTIndex()).toString().trim();210 value = value.equals("") ? "" : value;211 cellList.add(thisColumn, value);212 checkRowIsNull(value); //如果里面某个单元格含有值,则标识该行不为空行213 }214 break;215 case NumberRecord.sid: //单元格为数字类型216 NumberRecord numrec = (NumberRecord) record;217 curRow = thisRow = numrec.getRow();218 thisColumn = numrec.getColumn();219 220 //第一种方式221 //value = formatListener.formatNumberDateCell(numrec).trim();//这个被写死,采用的m/d/yy h:mm格式,不符合要求222 223 //第二种方式,参照formatNumberDateCell里面的实现方法编写224 Double valueDouble=((NumberRecord)numrec).getValue();225 String formatString=formatListener.getFormatString(numrec);226 if (formatString.contains("m/d/yy")){227 formatString="yyyy-MM-dd hh:mm:ss";228 }229 int formatIndex=formatListener.getFormatIndex(numrec);230 value=formatter.formatRawCellContents(valueDouble, formatIndex, formatString).trim();231 232 value = value.equals("") ? "" : value;233 //向容器加入列值234 cellList.add(thisColumn, value);235 checkRowIsNull(value); //如果里面某个单元格含有值,则标识该行不为空行236 break;237 default:238 break;239 }240 241 //遇到新行的操作242 if (thisRow != -1 && thisRow != lastRowNumber) {243 lastColumnNumber = -1;244 }245 246 //空值的操作247 if (record instanceof MissingCellDummyRecord) {248 MissingCellDummyRecord mc = (MissingCellDummyRecord) record;249 curRow = thisRow = mc.getRow();250 thisColumn = mc.getColumn();251 cellList.add(thisColumn, "");252 }253 254 //更新行和列的值255 if (thisRow > -1)256 lastRowNumber = thisRow;257 if (thisColumn > -1)258 lastColumnNumber = thisColumn;259 260 //行结束时的操作261 if (record instanceof LastCellOfRowDummyRecord) {262 if (minColums > 0) {263 //列值重新置空264 if (lastColumnNumber == -1) {265 lastColumnNumber = 0;266 }267 }268 lastColumnNumber = -1;269 270 if (flag&&curRow!=0) { //该行不为空行且该行不是第一行,发送(第一行为列名,不需要)271 ExcelReaderUtil.sendRows(filePath, sheetName, sheetIndex, curRow + 1, cellList); //每行结束时,调用sendRows()方法272 totalRows++;273 }274 //清空容器275 cellList.clear();276 flag=false;277 }278 }279 280 /**281 * 如果里面某个单元格含有值,则标识该行不为空行282 * @param value283 */284 public void checkRowIsNull(String value){285 if (value != null && !"".equals(value)) {286 flag = true;287 }288 }289 }

2.2.4 辅助类ExcelReaderUtil

调用ExcelXlsReader类和ExcelXlsxReader类对excel2003和excel2007两个版本进行大批量数据读取:

1 package org.poi; 2  3 import java.util.List; 4  5 /** 6  * @author y 7  * @create 2018-01-19 0:13 8  * @desc 9  **/10 public class ExcelReaderUtil {11     //excel2003扩展名12     public static final String EXCEL03_EXTENSION = ".xls";13     //excel2007扩展名14     public static final String EXCEL07_EXTENSION = ".xlsx";15 16     /**17      * 每获取一条记录,即打印18      * 在flume里每获取一条记录即发送,而不必缓存起来,可以大大减少内存的消耗,这里主要是针对flume读取大数据量excel来说的19      * @param sheetName20      * @param sheetIndex21      * @param curRow22      * @param cellList23      */24     public static void sendRows(String filePath, String sheetName, int sheetIndex, int curRow, List
cellList) {25 StringBuffer oneLineSb = new StringBuffer();26 oneLineSb.append(filePath);27 oneLineSb.append("--");28 oneLineSb.append("sheet" + sheetIndex);29 oneLineSb.append("::" + sheetName);//加上sheet名30 oneLineSb.append("--");31 oneLineSb.append("row" + curRow);32 oneLineSb.append("::");33 for (String cell : cellList) {34 oneLineSb.append(cell.trim());35 oneLineSb.append("|");36 }37 String oneLine = oneLineSb.toString();38 if (oneLine.endsWith("|")) {39 oneLine = oneLine.substring(0, oneLine.lastIndexOf("|"));40 }// 去除最后一个分隔符41 42 System.out.println(oneLine);43 }44 45 public static void readExcel(String fileName) throws Exception {46 int totalRows =0;47 if (fileName.endsWith(EXCEL03_EXTENSION)) { //处理excel2003文件48 ExcelXlsReader excelXls=new ExcelXlsReader();49 totalRows =excelXls.process(fileName);50 } else if (fileName.endsWith(EXCEL07_EXTENSION)) {
//处理excel2007文件51 ExcelXlsxReader excelXlsxReader = new ExcelXlsxReader();52 totalRows = excelXlsxReader.process(fileName);53 } else {54 throw new Exception("文件格式错误,fileName的扩展名只能是xls或xlsx。");55 }56 System.out.println("发送的总行数:" + totalRows);57 }58 59 public static void main(String[] args) throws Exception {60 String path="C:\\Users\\y****\\Desktop\\TestSample\\H_20171226_***_*****_0430.xlsx";61 ExcelReaderUtil.readExcel(path);62 }63 }

github地址

3. 参考资料:

 

转载地址:http://lycii.baihongyu.com/

你可能感兴趣的文章
Android 混合Flutter之产物集成方式
查看>>
Flutter混合开发二-FlutterBoost使用介绍
查看>>
Flutter 混合开发框架模式探索
查看>>
Flutter 核心原理与混合开发模式
查看>>
Flutter Boost的router管理
查看>>
Android Flutter混合编译
查看>>
微信小程序 Audio API
查看>>
[React Native]react-native-scrollable-tab-view(进阶篇)
查看>>
Vue全家桶+Mint-Ui打造高仿QQMusic,搭配详细说明
查看>>
React Native for Android 发布独立的安装包
查看>>
React Native应用部署/热更新-CodePush最新集成总结(新)
查看>>
react-native-wechat
查看>>
基于云信的react-native聊天系统
查看>>
网易云音乐移动客户端Vue.js
查看>>
ES7 await/async
查看>>
ES7的Async/Await
查看>>
React Native WebView组件实现的BarCode(条形码)、(QRCode)二维码
查看>>
每个人都能做的网易云音乐[vue全家桶]
查看>>
JavaScript专题之数组去重
查看>>
Immutable.js 以及在 react+redux 项目中的实践
查看>>