Friday, May 15, 2009

Recursivly Zipping a directory in Java

There are times we need to package and compress group of files. Java has out-of-the-box support for Zip compression algorithm.
By taking advantage of two classes: ZipOutputStream, ZipEntry we can easily compress any set of files of any size.
The class ZipOutputStream is similar to any other OutputStream class. It allows writing chunk of information to the stream. The class ZipEntry defines a single entry in the created Zip file. An entry is actually a file we would like to archive and compress. Zip archiving method made it very easy, since we don't have to deal with directories in the Zip file at all. In the entry we have to specify the file we would like to add along with its path or relative path. For each file we add to the stream we need to open a new entry.
We would like to use Java ZipOutputStream and ZipEntry to construct a method that gets any directory and zip it to a single Zip file. We will pay attention to two things:

  • All files and directories under the given directory should be recursively zipped.
  • The path of all zipped files will be relative to the given directory.
  • It will be possible to Zip all file to a new Zip file or to a Stream.

Java made all the hard work for us, hiding the complexity of the Zip algorithm. All we has to do is:

  • Create a ZipOutputStream instance.
  • Scan all files and directories of the given directory.
  • For each file we find in the directory:
    • Find file relative path. This is the path starting from the directory we would like to Zip.
    • Add new file entry using putNextEntry method of ZipOutputStream instance and ZipEntry class. This looks something like: zipOutputStream.putNextEntry(new ZipEntry(fileRelativePath)).
    • Read file and write it to Zip stream.
    • Close read file.
  • For each directory we find in the directory:
    • Recursively call our Zip method with the new directory.
  • When all files and directory has been processed: Close Zip stream.

And, this is how it looks in Java code:

package com.bashan.blog.zip;
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipUtil {
  private static final int BUFFER_SIZE = 1024 * 4;
  public static void zipDir(String dir, OutputStream out) throws IOException {
    ZipOutputStream zipOutputStream = null;
    if (out == null) {
      throw new NullPointerException("No output stream supplied");
    } else {
      try {
        zipOutputStream = new ZipOutputStream(out);
        int relativePos = dir.length() + 1;
        zipDir(new File(dir), zipOutputStream, relativePos);
      }
      finally {
        if (zipOutputStream != null) {
          zipOutputStream.close();
        }
      }
    }
  }
  public static void zipDir(String dir, String zipFilename) throws IOException {
    FileOutputStream fileOutputStream = null;
    try {
      fileOutputStream = new FileOutputStream(zipFilename);
      zipDir(dir, fileOutputStream);
    }
    finally {
      if (fileOutputStream != null) {
        fileOutputStream.close();
      }
    }
  }
  private static void zipDir(File dir, ZipOutputStream zipOutputStream, int relativePos) throws IOException {
    if (dir.exists() && dir.isDirectory()) {
      File[] files = dir.listFiles();
      for (File file : files) {
        if (file.isDirectory()) {
          zipDir(file, zipOutputStream, relativePos);
        } else {
          InputStream in = null;
          try {
            String filename = file.getPath();
            zipOutputStream.putNextEntry(new ZipEntry(filename.substring(relativePos)));
            in = new FileInputStream(file);
            int len;
            byte[] buf = new byte[BUFFER_SIZE];
            while ((len = in.read(buf)) != -1) {
              zipOutputStream.write(buf, 0, len);
            }
            zipOutputStream.closeEntry();
          }
          finally {
            if (in != null) {
              in.close();
            }
          }
        }
      }
    }
  }
  public static void main(String[] args) throws Exception {
    zipDir("C:\\some\\dir", "C:\\somedir.zip");
  }
}

On the bottom of the class there is a small main program showing an example of Zipping a directory to a file.

You can download the class by pressing here.

No comments:

Post a Comment