Pregunta

Estoy buscando escribir en un archivo de Excel (.xls MS Excel 2003 Format) programáticamente usando Java. Los archivos de salida de Excel pueden contener ~ 200,000 filas que planeo dividir sobre el número de hojas (64k filas por hoja, debido al límite de Excel).

He intentado usar las API de Apache POI, pero parece ser un cerdo de memoria debido al modelo de objeto API. Me veo obligado a agregar celdas/hojas al objeto de libro de trabajo en la memoria y solo una vez que se agregan todos los datos, ¡puedo escribir el libro de trabajo en un archivo! Aquí hay una muestra de cómo el Apache recomienda que escriba archivos de Excel usando su API:

Workbook wb = new HSSFWorkbook();
Sheet sheet = wb.createSheet("new sheet");

//Create a row and put some cells in it
Row row = sheet.createRow((short)0);

// Create a cell and put a value in it.
Cell cell = row.createCell(0);
cell.setCellValue(1);

// Write the output to a file
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
wb.write(fileOut);
fileOut.close();

Claramente, escribir ~ 20k filas (con unas 10-20 columnas en cada fila) me da el temido "java.lang.outOfMemoryError: Java Heap Space".

He intentado aumentar el montón inicial de JVM y el tamaño máximo del montón usando los parámetros XMS y XMX como XMS512M y XMX1024. Todavía no puedo escribir más de 150k filas en el archivo.

Estoy buscando una forma de transmitir a un archivo de Excel en lugar de construir todo el archivo en la memoria antes de escribirlo en el disco, lo que con suerte ahorrará mucho uso de la memoria. Se agradecería cualquier API o soluciones alternativas, pero estoy restringido al uso de Java. ¡Gracias! :)

¿Fue útil?

Solución

Todas las API de Java existentes intentan construir todo el documento en RAM a la vez. Intente escribir un archivo XML que se ajuste al nuevo formato de archivo XSLX en su lugar. Para comenzar, sugiero construir un archivo pequeño en el formulario deseado en Excel y guardarlo. Luego ábralo y examine la estructura y reemplace las piezas que desee.

Wikipedia tiene un buen artículo sobre el formato general.

Otros consejos

Tratar de usar Sxssf Libro de trabajo, eso es genial para los enormes documentos XLS, su documento de construcción y no coma Ram en absoluto, porque usando NIO

Tuve que dividir mis archivos en varios archivos de Excel para superar la excepción de espacio de montón. Pensé que alrededor de 5k filas con 22 columnas eran de eso, por lo que acababa de hacer mi lógica para que cada fila de 5k terminara el archivo, iniciara una nueva y simplemente numerara los archivos en consecuencia.

En los casos en que tenía más de 20k filas para escribir, tendría más de 4 archivos diferentes que representan los datos.

Eche un vistazo al Serializador HSSF del Proyecto Cocoon.

El serializador HSSF captura eventos de saxo y crea una hoja de cálculo en el formato XLS utilizado por Microsoft Excel

También está Jexcelapi, pero usa más memoria. Creo que debería crear el archivo .csv y abrirlo en Excel. Le permite pasar muchos datos, pero no podrá hacer ninguna "magia de Excel".

Considere usar el formato CSV. De esta manera, ya no está limitado por la memoria: bien, tal vez solo durante la prepopulación de los datos para CSV, pero esto también se puede hacer de manera eficiente, por ejemplo, consultando subconjuntos de filas de DB usando, por ejemplo, LIMIT/OFFSET e inmediatamente escríbelo en el archivo en lugar de transportar todo el contenido de la tabla de DB en la memoria de Java antes de escribir cualquier línea. La limitación de Excel de la cantidad de filas en una "hoja" aumentará a aproximadamente un millón.

Dicho esto, si los datos realmente provienen de un DB, entonces reconsideraría mucho si Java es la herramienta adecuada para esto. La mayoría de los DB decentes tienen una función de exportación a CSV que puede hacer esta tarea indudablemente mucho más eficiente. En caso de por ejemplo mysql, puede usar el LOAD DATA INFILE comando para esto.

Desarrollamos una biblioteca Java para este propósito y actualmente está disponible como proyecto de código abierto https://github.com/jbaliuka/x4j-analytic . Lo usamos para informes operativos. Generamos enormes archivos de Excel, ~ 200,000 deberían funcionar sin problemas, Excel también logra abrir dichos archivos. Nuestro código utiliza POI para cargar la plantilla, pero el contenido generado se transmite directamente a Archivo sin XML u capa de modelo de objeto en la memoria.

¿Este problema de memoria ocurre cuando inserta datos en la celda o cuando realiza el cálculo/generación de datos?

Si va a cargar archivos en un Excel que consiste en formato de plantilla estática predefinida, entonces es mejor guardar una plantilla y reutilizar múltiples tiempo. Normalmente, los casos de plantilla ocurren cuando va a generar un informe de ventas diario, etc.

De lo contrario, cada vez que necesita crear una nueva fila, borde, columna, etc. desde cero.

Hasta ahora, Apache POI es la única opción que encontré.

"Claramente, escribir ~ 20k filas (con unas 10-20 columnas en cada fila) me da el temido" java.lang.ouTofMemoryError: Java Heap Space "."

"Enterprise It"

Lo que puede hacer es realizar la inserción de datos por lotes. Cree una tabla de QueUetask, cada vez después de generar 1 página, descanse durante segundos, luego continúe la segunda porción. Si se preocupa por los cambios de datos dinámicos durante su tarea de cola, primero puede obtener la clave principal en Excel (ocultando y bloqueando la columna desde la vista del usuario). La primera ejecución será la clave primaria insertar, luego la segunda cola en adelante se leerá en el bloc de notas y hará la parte de la tarea por porción.

Hicimos algo bastante similar, la misma cantidad de datos, y tuvimos que cambiar a Jexcelapi porque POI es muy pesado en los recursos. Prueba Jexcelapi, ¡no te arrepentirás cuando tengas que manipular grandes archivos de Excel!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top