当前位置:   article > 正文

excel处理几十万行数据_大数据技术 POI读写大数据量excel如何解决超过几万行而导致内存溢出的问题...

excelpoi 处理20万数据异常

本篇教程探讨了大数据技术 POI读写大数据量excel如何解决超过几万行而导致内存溢出的问题,希望阅读本篇文章以后大家有所收获,帮助大家对大数据技术的理解更加深入。

<

1. Excel2003与Excel2007

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

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

2. 大批量数据读写

2.1 大批量数据写入

写入可以采用SXSSFWorkbook

2.2 大批量数据读取

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

pom.xml所需jar包:

2   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

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 

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 filename

134      * @throws Exception

135      */

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()) { //遍历sheet

147             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 uri

162      * @param localName

163      * @param name

164      * @param attributes

165      * @throws SAXException

166      */

167     @Override

168     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 ch

201      * @param start

202      * @param length

203      * @throws SAXException

204      */

205     @Override

206     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 uri

214      * @param localName

215      * @param name

216      * @throws SAXException

217      */

218     @Override

219     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 

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 attributes

284      */

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,B1

292

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      * @return

330      */

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                 // 对日期字符串作特殊处理,去掉T

372                 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,最后一列列名是XFD

383         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 

398             if (isPre) {

399                 for (int i = 0; i 

400                     str = let + str;

401                 }

402             } else {

403                 for (int i = 0; i 

404                     str = str + let;

405                 }

406             }

407         }

408         return str;

409     }

410

411     /**

412      * @return the exceptionMessage

413      */

414     public String getExceptionMessage() {

415         return exceptionMessage;

416     }

417 }

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 监听方法,处理Record

120      * 处理每个单元格

121      * @param record

122      */

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: //开始处理每个sheet

134                 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 value

283      */

284     public void checkRowIsNull(String value){

285         if (value != null && !"".equals(value)) {

286             flag = true;

287         }

288     }

289 }

辅助类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 sheetName

20      * @param sheetIndex

21      * @param curRow

22      * @param cellList

23      */

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 }

本文由职坐标整理发布,学习更多的大数据技术相关知识,请关注职坐标大技术云计算大技术技术频道!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/88826
推荐阅读
相关标签
  

闽ICP备14008679号