2011-05-13 15 views
11

POI (나는 xls와 xlsx 형식을 모두 가지고 있음)를 읽으려고하는 스프레드 시트가 있지만이 경우 xls 파일에 문제가 있습니다. 내 스프레드 시트에는 약 10,000 개의 행과 75 개의 열이 있으며 읽기에는 몇 분이 걸릴 수 있습니다 (Excel이 몇 초 안에 열림). 전체 파일을 메모리로 읽는 대신 이벤트 기반 읽기를 사용하고 있습니다. 내 코드는 다음과 같습니다. 지금은 다소 지저분하지만 실제로는 POI 예제에서 주로 복사 된 긴 switch 문입니다.Apache POI Java 스프레드 시트의 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가 잘 작동하는 xls입니까? 나에게 그것은 반대 다. 많은 행을 가진 파일을 작성하는 것은 xls에 대해 몇 메가 바이트의 힙을 사용하지만 xlsx에는 2GB조차 충분하지 않다. 출력에 X 행 이상이있는 경우 xls로 폴백해야합니다. – rlovtang

+0

@rlovtang, xlsx가 더 느립니다. xls와 xlsx를 모두 처리해야하기 때문에 JExcel과 같은 것 대신 POI를 사용한다는 의미였습니다. –

답변

6

나는 또한 수천 개의 대형 Excel 파일을 처리했으며 POI는 매우 빠릅니다. 파일을로드하는 데 Excel 자체에서 약 1 분이 걸렸습니다. 그래서 문제가 POI 코드에 있다는 것을 확인할 것입니다.

+0

제 답변을 참조하십시오, 당신은 정확합니다. –

1

좀 더 자세한 프로파일 링을 수행했는데 실제로 문제가 POI 외부의 코드에있는 것처럼 보입니다. 방금 병목 현상이라고 생각했지만 올바르지 않다고 생각합니다.

+2

코드의 위치를 ​​자세히 설명해 주실 수 있습니까? 그것은 당신 자신의 코드입니까, 아니면 제 3 자 항아리입니까? – davo

+1

그것은 내 자신의 코드입니다. 나는 실수로 텍스트 필드를 매우 비효율적으로 파싱하여 날짜 값을 가지고 있는지 (사용자가 텍스트를 날짜 형식으로 입력하지 않은 셀에 입력 한 경우) 텍스트 형식의 구문 분석을 시도했다. –

2

poi-beta3에서 소개 된 스트리밍 hssf를 사용하려고합니다. 이로 인해 1000 개 이상의 열이있는 대형 스프레드 시트의 메모리 문제가 해결되었습니다.

1

큰 엑셀 파일을 생성하기 위해 Apache POI를 사용하는 경우 sheet.autoSizeColumn ((short) p)를 메모하십시오. 이는 성능에 영향을 미치기 때문입니다. 당신 F

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

+1

기사에 autoSizeColumn이 모든 행이 추가 될 때마다 루프에서 호출되고 모든 행이 완료되면 루프 이후에 호출되지 않기 때문에 이는 사실이 아닐 수 있습니다. – Somu

11

큰 엑셀 파일을 생성하는 아파치 POI를 사용하고, 다음 줄을 유의하시기 바랍니다 :

sheet.autoSizeColumn((short) p);

을이 성능을 저하 때문이다.

+2

_ 성능에 어떤 영향을 미칩니 까? 도움이 될 것인가, 아니면 방해 할 것인가? –

+1

이것은 정말로 도움이되었습니다. 나는 간단한 3000 라인 출력을 10 초 동안 2 초 (문자 그대로)까지 실행했습니다. 코드를 쓰면 속도가 느려지므로이 문제가 있음을 알 수 있습니다. @sams 감사합니다. – Dennis

관련 문제