我有一个电子表格,我正在尝试用POI阅读(我有xls和xlsx格式),但在这种情况下,问题出在xls文件中。我的电子表格大约有10,000行和75列,读取它可能需要几分钟(尽管Excel会在几秒钟内打开)。我正在使用基于事件的阅读,而不是将整个文件读入内存。我的代码的内容如下。现在它有点乱,但它实际上只是一个很长的转换语句,主要是从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);
答案 0 :(得分:13)
如果您使用Apache POI生成大型Excel文件,请注意以下行:
sheet.autoSizeColumn((short) p);
因为这会降低性能。
答案 1 :(得分:6)
我还对数千个大型excel文件进行了一些处理,在我看来,POI非常快。加载excel文件在Excel本身也花了大约1分钟。所以我会确认问题出自POI代码
答案 2 :(得分:3)
我会尝试使用poi-beta3中引入的流式hssf。这有助于1000多列的大型电子表格中的内存问题。
答案 3 :(得分:1)
我做了一些更详细的分析,看起来问题实际上是在POI之外的代码中。我只是认为这是瓶颈,但我认为这是不正确的。
答案 4 :(得分:1)
如果您使用Apache POI生成大型Excel文件,请注意sheet.autoSizeColumn((短)p);因为这会影响性能。
http://stanicblog.blogspot.sg/2013/07/generate-large-excel-report-by-using.html