2009-11-20 14 views
8

Ho la necessità di comprimere un file Big (~ 450 Mbyte) tramite la classe Java ZipOutputStream. Questa grande dimensione causa un problema di errore "OutOfMemory" del mio spazio heap JVM. Ciò accade perché il metodo "zos.write (...)" memorizza TUTTO il contenuto del file da comprimere in un array di byte interno prima di comprimerlo.Per comprimere un file grande in 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 soluzione naturale sarà quello di allargare lo spazio di memoria heap della JVM, ma vorrei sapere se c'è un metodo di scrivere questi dati in modo streaming. Non ho bisogno di un alto tasso di compressione in modo da poter cambiare anche l'algoritmo.

qualcuno ha un'idea a riguardo?

+1

Quanto è grande BUFFER? –

+0

Come ho scritto 2048 – robob

risposta

8

In base al tuo commento alla risposta di Sam, hai ovviamente creato un ZipOutputStream, che avvolge un ByteArrayOutputStream. ByteArrayOutputStream, naturalmente, memorizza nella cache il risultato compresso in memoria. Se vuoi che sia scritto su disco, devi avvolgere lo ZipOutputStream attorno a un FileOutputStream.

+0

Ok Capisco cosa mi hai detto, ma i dati compressi sono circa 60 MByte ... in basso per eseguire un errore di heap "OutOfSpace". Che ne pensi? Devo impostare un Xmx1024m per essere buono! Probabilmente è un mio errore! – robob

+2

+1, utilizzare FileOutputStream per scrivere il file zip su disco oppure, se si desidera eseguire lo streaming direttamente sul browser, utilizzare HttpServletResponse outputStream. –

+1

Quando 60 MBytes hanno spento la memoria, si stavano utilizzando le impostazioni JVM predefinite? Se è così, allora suona bene. Anche se la JVM è in esecuzione a 64 M di dimensione heap a un certo punto, ByteArrayOutputStream dovrà espandere tale byte [] array ... che significa una copia completa. – PSpeed

3

C'è una libreria chiamata TrueZip che in passato ho usato con buon successo per fare questo genere di cose.

Non posso garantire che funzioni meglio sul fronte di buffering. So che fa un sacco di cose con la sua codifica piuttosto che a seconda dell'API Zip di JDK.

Quindi vale la pena provare, secondo me.

1

ZipOutputStream è basato su flusso, non trattiene memoria. Il tuo BUFFER potrebbe essere troppo grande.

+0

My Buffer è 2048 byte e non penso sia troppo grande! questa è l'eccezione: Exception in thread java.lang.OutOfMemoryError "principale": lo spazio di heap Java \t a java.util.Arrays.copyOf (Arrays.java:2786) \t a java.io.ByteArrayOutputStream. scrittura (ByteArrayOutputStream.java:94) \t a java.util.zip.DeflaterOutputStream.deflate (DeflaterOutputStream.java:161) \t a java.util.zip.DeflaterOutputStream.write (DeflaterOutputStream.java:118) \t a java .util.zip.ZipOutputStream.write (ZipOutputStream.java:272) – robob

0

Mi chiedo se è perché si sta memorizzando il contenuto in uno ZipEntry, forse in pratica carica tutto il suo contenuto prima di scrivere lo ZipEntry. Devi usare Zip? Se è solo un flusso di dati che è necessario comprimere, si potrebbe invece esaminare GZIPOutputStream. Credo che non avrebbe lo stesso problema.

Spero che questo aiuti.

+0

Ho bisogno di memorizzare un contenuto di directory in un file Zip per inviare tramite il servizio Web – robob

+2

Suoni l Ho una cattiva idea se hai oggetti così grandi nella tua risposta. Prendi in considerazione la possibilità di restituire un URL dal luogo in cui il file zip può essere ripresentato. I servlet semplici consentono una risposta di streaming basata su byte. –

+0

hai ragione penso che questa sia la scelta giusta da ottenere. – robob

Problemi correlati