2011-05-13 101 views
11

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

使用事件模型的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

它是慢的xlsx和xlsx,它工作正常吗?对我来说,它是相反的,编写一个包含许多行的文件只需要几兆字节的堆,但即使是2GB也不足以用于xlsx。如果输出超过X行,我需要回退到xls – rlovtang 2011-05-13 13:45:25

+0

@rlovtang,xlsx更慢。我的意思是我使用POI而不是JExcel,因为我需要处理xls和xlsx。 – 2011-05-13 13:46:12

回答

6

我也做了一些处理数以千计的大型excel文件,在我看来,POI非常快。加载Excel文件在Excel本身中也花费了大约1分钟的时间。所以我会确认问题在于POI代码

+0

看到我的回答,你是对的。 – 2011-05-13 14:33:45

1

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

+2

你能提供更多细节到代码的位置吗?是你自己的代码还是第三方罐子? – davo 2012-01-18 13:12:37

+1

这是我自己的代码。我错误地试图对文本字段进行一些非常低效的解析,以查看它们是否具有日期值(用于在用户输入文本时将日期记录到没有日期格式的单元格中)。 – 2012-01-18 23:45:22

2

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

11

F你使用Apache POI生成大excel文件,请注意以下行:

sheet.autoSizeColumn((short) p);

因为这会降低性能。

+2

_它会影响性能吗?它会帮助还是会阻碍它? – 2014-02-05 12:29:20

+1

这真的帮了我,我正在运行一个简单的3000行输出,从10分钟缩短到2秒(字面上)。你会注意到这个问题,因为你的代码在写出时会变慢。谢谢@sams – Dennis 2015-02-07 19:25:52