适用于大型电子表格的Apache POI Java Excel性能

我有一个电子表格,我试图阅读与POI(我有xls和xlsx格式),但在这种情况下,问题是与xls文件。 我的电子表格大约有10,000行和75列,读取它可能需要几分钟时间(尽pipeExcel会在几秒钟内打开)。 我正在使用基于事件的阅读,而不是将整个文件读入内存。 我的代码的肉在下面。 现在有点乱,但是这实际上只是一个很长的switch语句,大部分都是从POI的例子中复制而来的。

使用事件模型的POI性能如此之慢是典型的吗? 我有什么办法来加速这个吗? 我觉得我的申请几分钟是不能接受的。

POIFSFileSystem poifs = new POIFSFileSystem(fis); InputStream din = poifs.createDocumentInputStream("Workbook"); try { HSSFRequest req = new HSSFRequest(); listener = new FormatTrackingHSSFListener(new HSSFListener() { @Override public void processRecord(Record rec) { thisString = null; int sid = rec.getSid(); switch (sid) { case SSTRecord.sid: strTable = (SSTRecord) rec; break; case LabelSSTRecord.sid: LabelSSTRecord labelSstRec = (LabelSSTRecord) rec; thisString = strTable.getString(labelSstRec .getSSTIndex()).getString(); row = labelSstRec.getRow(); col = labelSstRec.getColumn(); break; case RKRecord.sid: RKRecord rrk = (RKRecord) rec; thisString = ""; row = rrk.getRow(); col = rrk.getColumn(); break; case LabelRecord.sid: LabelRecord lrec = (LabelRecord) rec; thisString = lrec.getValue(); row = lrec.getRow(); col = lrec.getColumn(); break; case BlankRecord.sid: BlankRecord blrec = (BlankRecord) rec; thisString = ""; row = blrec.getRow(); col = blrec.getColumn(); break; case BoolErrRecord.sid: BoolErrRecord berec = (BoolErrRecord) rec; row = berec.getRow(); col = berec.getColumn(); byte errVal = berec.getErrorValue(); thisString = errVal == 0 ? Boolean.toString(berec .getBooleanValue()) : ErrorConstants .getText(errVal); break; case FormulaRecord.sid: FormulaRecord frec = (FormulaRecord) rec; switch (frec.getCachedResultType()) { case Cell.CELL_TYPE_NUMERIC: double num = frec.getValue(); if (Double.isNaN(num)) { // Formula result is a string // This is stored in the next record outputNextStringRecord = true; } else { thisString = formatNumericValue(frec, num); } break; case Cell.CELL_TYPE_BOOLEAN: thisString = Boolean.toString(frec .getCachedBooleanValue()); break; case Cell.CELL_TYPE_ERROR: thisString = HSSFErrorConstants .getText(frec.getCachedErrorValue()); break; case Cell.CELL_TYPE_STRING: outputNextStringRecord = true; break; } row = frec.getRow(); col = frec.getColumn(); break; case StringRecord.sid: if (outputNextStringRecord) { // String for formula StringRecord srec = (StringRecord) rec; thisString = srec.getString(); outputNextStringRecord = false; } break; case NumberRecord.sid: NumberRecord numRec = (NumberRecord) rec; row = numRec.getRow(); col = numRec.getColumn(); thisString = formatNumericValue(numRec, numRec .getValue()); break; case NoteRecord.sid: NoteRecord noteRec = (NoteRecord) rec; row = noteRec.getRow(); col = noteRec.getColumn(); thisString = ""; break; case EOFRecord.sid: inSheet = false; } if (thisString != null) { // do something with the cell value } } }); req.addListenerForAllRecords(listener); HSSFEventFactory factory = new HSSFEventFactory(); factory.processEvents(req, din); 

我也做了一些处理与成千上万的大型Excel文件,在我看来,POI是非常快的。 加载Excel文件在Excel本身也花了大约1分钟。 所以我会确认问题在于POI代码

如果您使用的是Apache POI来生成大型的excel文件,请注意以下几行:

sheet.autoSizeColumn((short) p);

因为这会降低性能。

我会尝试使用poi-beta3中引入的stream式hssf。 这有助于1000列以上的大型电子表格中的内存问题。

我做了一些更详细的分析,看起来问题实际上是POI以外的代码。 我只是认为这是瓶颈,但我认为这是不正确的。

如果您使用的是Apache POI来生成大型的excel文件,请注意sheet.autoSizeColumn((short)p); 因为这会影响性能。

http://stanicblog.blogspot.sg/2013/07/generate-large-excel-report-by-using.html