2011-05-13 125 views
11

Tengo una hoja de cálculo que estoy tratando de leer con POI (tengo formatos xls y xlsx), pero en este caso, el problema es con el archivo xls. Mi hoja de cálculo tiene aproximadamente 10,000 filas y 75 columnas, y leerlas puede tomar varios minutos (aunque Excel abre en unos pocos segundos). Estoy usando la lectura basada en eventos, en lugar de leer todo el archivo en la memoria. La carne de mi código está abajo. En este momento está un poco desordenado, pero en realidad solo se trata de una declaración de conmutación larga que se copió principalmente de los ejemplos de puntos de interés.Apache POI Java Excel Rendimiento para hojas de cálculo grandes

¿Es típico que el rendimiento de los puntos de interés con el modelo de eventos sea tan lento? ¿Hay algo que haga para acelerar esto? Creo que varios minutos serán inaceptables para mi aplicación.

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

¿Es xls lento y xlsx que funciona bien? Para mí es opuesto, escribir un archivo con muchas filas solo usa algunos megabytes de heap para xls, pero incluso 2 GB no fueron suficientes para xlsx. Necesito recurrir a xls si la salida tiene más de X filas – rlovtang

+0

@rlovtang, xlsx es aún más lento. Solo quise decir que estoy usando POI en lugar de algo como JExcel porque necesito lidiar con xls y xlsx. –

Respuesta

6

También realicé algunos procesos con miles de grandes archivos de Excel y, en mi opinión, POI es muy rápido. Cargar los archivos de Excel también tomó aproximadamente 1 minuto en Excel. Así que confirmaría que el problema radica en el código de POI

+0

Vea mi respuesta, está en lo correcto. –

1

Hice algunos perfiles más detallados y parece que el problema está realmente en el código fuera de POI. Simplemente asumí que este era el cuello de botella, pero creo que esto es incorrecto.

+2

¿Puede proporcionar más detalles sobre dónde estaba el código? ¿Fue tu propio código o frascos de terceros? – davo

+1

Era mi propio código. Intenté equivocadamente hacer un análisis muy ineficiente de campos de texto para ver si tenían valores de fecha (para cuando los usuarios ingresaban fechas de texto en celdas que no tenían un formato de fecha). –

2

Intentaré utilizar el hssf de transmisión introducido en poi-beta3. Esto ayudó a los problemas de memoria en hojas de cálculo grandes con más de 1000 columnas.

11

f que está utilizando Apache POI para generar gran archivo de Excel, por favor tome en cuenta la siguiente línea:

sheet.autoSizeColumn((short) p);

Debido a esto degradará el rendimiento.

+2

_¿Cómo afectará el rendimiento? ¿Lo ayudará o lo impedirá? –

+1

Esto realmente me ayudó, estaba ejecutando una salida de línea simple de 3000 tomando 10 minutos hasta 2 segundos (literalmente). Notará este problema ya que su código se ralentiza en la escritura. Gracias @sams – Dennis

Cuestiones relacionadas