views:

621

answers:

4

I have the need to compress a one Big file (~450 Mbyte) through the Java class ZipOutputStream. This big dimension causes a problem of "OutOfMemory" error of my JVM Heap Space. This happens because the "zos.write(...)" method stores ALL the file content to compress in an internal byte array before compressing it.

      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();

The natural solution will be to enlarge the heap memory space of the JVM, but I would like to know if there is a method to write this data in a streaming manner. I do not need an high compression rate so I could change the algorithm too.

does anyone have an idea about it?

A: 

There's a library called TrueZip that I've used with good success in the past to do this kind of thing.

I cannot guarantee it does better on the buffering front. I do know that it does a lot of stuff with its own coding rather than depending on the JDK's Zip API.

So it's worth a try, in my opinion.

Carl Smotricz
+1  A: 

ZipOutputStream is stream-based, it doesn't hold onto memory. Your BUFFER may be too large.

Sam Barnum
My Buffer is 2048 byte and I don't think is too big!This is the Exception:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:2786) at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:94) at java.util.zip.DeflaterOutputStream.deflate(DeflaterOutputStream.java:161) at java.util.zip.DeflaterOutputStream.write(DeflaterOutputStream.java:118) at java.util.zip.ZipOutputStream.write(ZipOutputStream.java:272)
robob
A: 

I wonder if it's because you are storing the content in a ZipEntry, perhaps it basically loads all of its content before writing out the ZipEntry. Do you have to use Zip? If it's just one data stream you need to compress you might look into the GZIPOutputStream instead. I believe that it would not have the same problem.

Hope this helps.

cjstehno
I need to store a directory content in a Zip file to send through Web Service
robob
Sounds like a bad idea if you have such large objects in your response. Consider returning an URL instead from where the zip-file can be retreived. Plain servlets allow for a byte-based streaming response.
Thorbjørn Ravn Andersen
you are right I think this is the right choise to get.
robob
+5  A: 

According to your comment to Sam's response, you have obviously created a ZipOutputStream, which wraps a ByteArrayOutputStream. The ByteArrayOutputStream of course caches the compressed result in memory. If you want it written to disk, you have to wrap the ZipOutputStream around a FileOutputStream.

jarnbjo
Ok I understand what you told me but the compressed data is about 60 MByte...tot low to run an "OutOfSpace" heap error. What about it? I have to set a Xmx1024m to be good!Probably is a my mistake!
robob
+1, use a FileOutputStream to write the zip to disk, or if you want to stream it directly to the browser use the HttpServletResponse outputStream.
Sam Barnum
When 60 MBytes blew out memory were you using the default JVM settings? If so then that sounds about right. Even if your JVM is running at 64 M heap size at some point the ByteArrayOutputStream will need to expand that byte[] array... which means a full copy.
PSpeed