title: Randomly accessing a compressed file without using ZipFile (since ZipFile has a major bug)
body: <p>I know, I know, who would want to compress or uncompressed large files in java. Completely unreasonable. For the moment suspend disbelief and assume I have a good reason for uncompressing a large zip File.</p>
  
  <p>Issue 1: <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/zip/ZipFile.html" rel="nofollow noreferrer">ZipFile</a> has a <a href="http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=9dea65953f1524bbebc370dbf7a?bug_id=6280693" rel="nofollow noreferrer">bug (bug # 6280693)</a>, sun has fixed this in java 1.6 (Mustang). The fix isn't isn't helpful as our software needs to support java 1.4. The bug, as I understand it, works like this. When the following code is run, Java allocates a chunk of memory large enough to hold the entire file. </p>
  
  <pre><code>ZipFile zipFile = new ZipFile("/tmp/myFile.zip");
  </code></pre>
  
  <p>If /tmp/myFile.zip is 4gb, java allocates 4gb. This causes an out of a heap exception. A heap size of +4gb is unfortunately not an acceptable solution. =(</p>
  
  <p>Solution to issue 1: Use <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/ZipInputStream.html" rel="nofollow noreferrer">ZipInputStream</a>, to deal with the file as a stream and thus reduce and control the memory footprint.</p>
  
  <pre><code>byte[] buf = new byte[1024];
  FileInputStream fs = new FileInputStream("/tmp/myFile.zip")
  ZipInputStream zipIn = new ZipInputStream(fs);
  
  ZipEntry ze = zipIn.getNextEntry();
  
  while (ze != null){
    while ((int cr = zipIn.read(buf, 0, 1024)) &gt; -1) 
      System.out.write(buf, 0, len);
    ze = zipIn.getNextEntry();
  }
  </code></pre>
  
  <p>Issue 2: I would like access the ZipEntries randomly. That is, I would like to only uncompress one ZipEntry, without having to search through the entire stream. Currently I am building up a list of zipEntries, called zes:</p>
  
  <pre><code>        ZipInputStream zin = new ZipInputStream("/tmp/myFile.zip");
  
          ZipEntry ze = zin.getNextEntry();
          List&lt;ZipEntry&gt; zes = new ArrayList&lt;ZipEntry&gt;();
  
          while(ze!=null){
              zes.add(ze);
              ze = zin.getNextEntry();
          }
  </code></pre>
  
  <p>Then when I need to uncompress a particular zipEntry I iteratorate through all the zipEntries until I find the matching zipEntry, which I then uncompress.</p>
  
  <pre><code>        ZipEntry ze = in.getNextEntry();
          while (! ze.getName().equals(queryZe.getName())){
              ze = zin.getNextEntry();
          }
  
          int cr;
  
          while ((cr = zin.read(buf)) &gt; -1) 
              System.out.write(buf, 0, cr);
  </code></pre>
  
  <p>Quertion: ZipFile has the ability to randomly access ZipEntries.</p>
  
  <pre><code>new BufferedInputStream(zipFile.getInputStream(zipEntry));
  </code></pre>
  
  <p>How can I get this same ability without using ZipFile? </p>
  
  <p>Note that ZipInputStream has some rather <a href="https://stackoverflow.com/questions/826390/zipinputstream-doesnt-report-actual-i-e-compressed-bytes-read">strange</a> <a href="https://stackoverflow.com/questions/67275/reading-from-a-zipinputstream-into-a-bytearrayoutputstream/69489#69489">behavior</a>.</p>
  
  <p>Especially good documentation on java and ZipFiles can be found here:</p>
  
  <p><a href="http://commons.apache.org/compress/zip.html" rel="nofollow noreferrer">http://commons.apache.org/compress/zip.html</a></p>
  
  <p><strong>Notes on switching replacing sun ZipFile with apache commons ZipFile as suggested in the answers:</strong></p>
  
  <ol>
  <li>Sun's <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/ZipFile.html" rel="nofollow noreferrer">ZipFile.entries()</a> always returns the ZipEntries in the order in which they occur in the file, whereas apache commons <a href="http://commons.apache.org/compress/apidocs/org/apache/commons/compress/archivers/zip/ZipFile.html" rel="nofollow noreferrer">ZipFile.getEntries()</a> returns the entries in random order. This caused an interesting bug, because some code was assuming that the entries would be "in order".</li>
  </ol>