2009-11-20 30 views
8

Tengo la necesidad de comprimir un archivo grande (~ 450 Mbyte) a través de la clase Java ZipOutputStream. Esta gran dimensión causa un problema de error "OutOfMemory" de mi espacio de montón JVM. Esto sucede porque el método "zos.write (...)" almacena TODO el contenido del archivo para comprimirlo en una matriz de bytes interna antes de comprimirlo.Para comprimir un archivo grande en un ZIP con Java

  origin = new BufferedInputStream(fi, BUFFER); 
     ZipEntry entry = new ZipEntry(filePath); 
     zos.putNextEntry(entry); 

     int count; 
     while ((count = origin.read(data, 0, BUFFER)) != -1) 
     { 
      zos.write(data, 0, count); 
     } 
     origin.close(); 

La solución natural será la de ampliar el espacio de memoria de almacenamiento dinámico de la JVM, pero me gustaría saber si hay un método para escribir estos datos en una forma de streaming. No necesito una alta tasa de compresión, así que podría cambiar el algoritmo también.

¿alguien tiene una idea al respecto?

+1

¿Qué tan grande es BUFFER? –

+0

Como escribí 2048 – robob

Respuesta

8

Según su comentario a la respuesta de Sam, obviamente ha creado un ZipOutputStream, que envuelve un ByteArrayOutputStream. Por supuesto, ByteArrayOutputStream almacena en caché el resultado comprimido en la memoria. Si desea que se escriba en el disco, debe ajustar ZipOutputStream alrededor de FileOutputStream.

+0

Ok Entiendo lo que me dijo, pero los datos comprimidos son de aproximadamente 60 MByte ... tot low para ejecutar un error de montón "OutOfSpace". ¿Qué hay de eso? ¡Tengo que configurar un Xmx1024m para que sea bueno! ¡Probablemente sea un error mío! – robob

+2

+1, utilice un FileOutputStream para escribir el archivo comprimido en el disco o, si desea transmitirlo directamente al navegador, utilice HttpServletResponse outputStream. –

+1

Cuando 60 MBytes volcaron la memoria, ¿estaba utilizando la configuración de JVM predeterminada? Si es así, eso suena bien. Incluso si su JVM se ejecuta en un tamaño de almacenamiento intermedio de 64 M en algún punto, ByteArrayOutputStream necesitará expandir esa matriz de byte [] ... lo que significa una copia completa. – PSpeed

3

Hay una biblioteca llamada TrueZip que he utilizado con éxito en el pasado para hacer este tipo de cosas.

No puedo garantizar que funcione mejor en el frente del búfer. Sé que hace muchas cosas con su propia codificación en lugar de depender de la API Zip del JDK.

Así que vale la pena intentarlo, en mi opinión.

1

ZipOutputStream se basa en secuencias, no se aferra a la memoria. Su BÚFER puede ser demasiado grande.

+0

¡Mi buffer es de 2048 bytes y no creo que sea demasiado grande! Esta es la excepción: Excepción en hilo java.lang.OutOfMemoryError "principal": espacio de montón Java \t en java.util.Arrays.copyOf (Arrays.java:2786) \t en java.io.ByteArrayOutputStream. escribir (ByteArrayOutputStream.java:94) \t en java.util.zip.DeflaterOutputStream.deflate (DeflaterOutputStream.java:161) \t en java.util.zip.DeflaterOutputStream.write (DeflaterOutputStream.java:118) \t en java .util.zip.ZipOutputStream.write (ZipOutputStream.java:272) – robob

0

Me pregunto si es porque está almacenando el contenido en un ZipEntry, quizás básicamente carga todo su contenido antes de escribir el ZipEntry. ¿Tienes que usar Zip? Si solo necesita una secuencia de datos para comprimir, puede buscar en el GZIPOutputStream. Creo que no tendría el mismo problema.

Espero que esto ayude.

+0

Necesito almacenar un contenido de directorio en un archivo Zip para enviarlo a través del servicio web – robob

+2

Sonidos l Es una mala idea si tienes objetos tan grandes en tu respuesta. Considere devolver una URL en su lugar desde donde se puede recuperar el archivo comprimido. Los servlets simples permiten una respuesta de transmisión basada en bytes. –

+0

tienes razón, creo que esta es la elección correcta para obtener. – robob

Cuestiones relacionadas