Creating a ZIP file containing multiple compressed files in Java

A ZipOutputStream is able to create an outputstream containing several data streams converted into the ZIP format. The resulting outputstream is either compressed at a certain level (higher level means better compression) or uncompressed. These are the steps to take to create a ZIP stream:

   1) Create a ZipOutputStream, and pass it an outputstream sink 
      (typically a FileOutputStream)
   2) For every distinct data stream (eg. file in directory), create 
      a ZipEntry that contains information about the data stream (eg.
	compression level, optional comment, ...) and write that ZipEntry
	to the ZipOutputStream with the method <i>putNextEntry</i>.
   3) Read the actual data from the source (eg. file) and write it to the
      ZipOutputStream.
   4) Finalize the entry in the ZipOutputStream by calling <i>closeEntry</i>.
   5) Perform step 2, 3 and 4 until there are no more entries (or files) to zip.

Following example zips up all the .java files in the current directory into javafiles.zip.

Main.java:

import java.util.zip.*;
import java.io.*;
  
public class Main
{
   public static void main(String []args) {
      try {
         File dir = new File(".");
         String []filenames = dir.list();
 
         ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("javafiles.zip"));
         byte[] buffer = new byte[1024];
         int length;
 
         for (int i=0; i<filenames.length; i++) {
            if (filenames[i].endsWith(".java")) {
               FileInputStream fis = new FileInputStream(filenames[i]);
 
               ZipEntry ze = new ZipEntry(filenames[i]);
               zos.putNextEntry(ze);
  
               while ((length = fis.read(buffer)) >= 0) {
                  zos.write(buffer, 0, length);
               }
 
               fis.close();
               zos.closeEntry();
 
               System.out.println(filenames[i] + " " + ze.getCompressedSize()
                                  + "/" + ze.getSize()); 
            }
         }
 
         zos.close();    
      }
      catch(IOException e) {
         System.err.println(e);
      }
   }
}

You can change the compression method with setMethod. ZipOutputStream’s default compression method is DEFLATED which uses java.util.zip.Deflater. The only other method that is currently supported is STORED which doesn’t do any compression. When using this method, however, you must initialize the ZipEntry with a CRC-value and a file size of a datastream before you can write it to the ZipOutputStream otherwise it will throw the following exception:

   java.util.zip.ZipException: STORED entry missing size, compressed size, or crc-32

(the method DEFLATED doesn’t have this requirement). That sucks, cause you will have to process the data stream an extra time (to find out the CRC-value and file size).