Have you ever had the requirement to compress or uncompress files or byte streams from within your java applications? This requirement seems to be a common need for me in all sorts of applications from B2B data feeds to my client applications. Within my client applications I allow users to attach files to records and I compress them to conserve space before storing them on the server. Once I compress the byte stream, I usually do one of two things. I will either store the byte stream representing the compressed file directly into a BLOB column in my database, or I will write it to a file in a common file system location.

Below I will present my simple ZipUtil java class which allows us to easily compress and uncompress files. My class consists of two convenience methods that take a byte array and call either the java.util.zip.Deflater or java.util.zip.Inflater objects to compress/decompress the byte array, and then it returns the new byte array. These java classes provide support for general purpose compression/decompression using the ZLIB compression library.

This class is not designed to create Zip files per se, but rather to just compress and uncompress byte streams. I will present the class to you below:

/**
 * Copyright (c) 2002-2004 by Timothy E. Archer.  All rights reserved.
 *
 * $Id: ZipUtil.java,v 1.1 2004/07/07 02:55:03 tima Exp $
 *
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL TIMOTHY E. ARCHER BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */
package com.tima.util;

import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.nio.channels.*;
import java.nio.*;
import org.apache.log4j.*;

/**
 * General Zip utilities/helper methods.
 *
 *
 * @author  Tim Archer 10/29/03
 * @version $Revision: 1.1 $
 */
public class ZipUtil {

    /**
     * Compress a byte array using the java.util.zip.Deflater object
     * with BEST_COMPRESSION
     * and return a byte array containing the compressed bytes.
     *
     * @param input The byte array to compress.
     * @return byte[] The compressed byte array.
     * @throws Exception If an error occurs.
     */
    public static byte[] compressByteArray(byte[] input) throws Exception {

        //
        // Create the compressor with highest level of compression
        //
        Deflater compressor = new Deflater();
        compressor.setLevel(Deflater.BEST_COMPRESSION);

        //
        // Give the compressor the data to compress
        //
        compressor.setInput(input);
        compressor.finish();

        //
        // Create an expandable byte array to hold the compressed data.
        // You cannot use an array that's the same size as the orginal because
        // there is no guarantee that the compressed data will be smaller than
        // the uncompressed data.
        //
        ByteArrayOutputStream bos = new ByteArrayOutputStream(input.length);

        //
        // Compress the data
        //
        byte[] buf = new byte[1024];
        while (!compressor.finished()) {
            int count = compressor.deflate(buf);
            bos.write(buf, 0, count);
        }

        try {
            bos.close();
        } catch (IOException e) {
        }

        //
        // Get the compressed data
        //
        byte[] compressedData = bos.toByteArray();

        return compressedData;
    }

    /**
     * Uncompress a compressed byte array using the java.util.zip.Inflater
     * object and return a byte array containing the uncompressed bytes.
     *
     * @param compressedData The byte array to uncompress.
     * @return byte[] The uncompressed byte array.
     * @throws Exception If an error occurs.
     */
    public static byte[] uncompressByteArray(byte[] compressedData) throws Exception {
        //
        // Create the decompressor and give it the data to compress
        //
        Inflater decompressor = new Inflater();
        decompressor.setInput(compressedData);

        //
        // Create an expandable byte array to hold the decompressed data
        //
        ByteArrayOutputStream bos = new ByteArrayOutputStream(compressedData.length);

        //
        // Decompress the data
        //
        byte[] buf = new byte[1024];
        while (!decompressor.finished()) {
            try {
                int count = decompressor.inflate(buf);
                bos.write(buf, 0, count);
            } catch (DataFormatException e) {
            }
        }
        try {
            bos.close();
        } catch (IOException e) {
        }

        //
        // Get the decompressed data
        //
        byte[] decompressedData = bos.toByteArray();

        return decompressedData;
    }

    /**
     * Main - Main unit test procedure
     * @param args Command line arguments.
     *
     */
    public static void main(String args[]) {
	try {
          System.out.println("ZipUtil starting.");
          //
          //Read the file into a byte array. I know, this is not the best way
          //to do this, its just simple for a test
          //
          FileInputStream fis = new FileInputStream("c:\\temp\\test.txt");
          FileChannel fc = fis.getChannel();
          // fc.size returns the size of the file which backs the channel
          byte[] data = new byte[(int) fc.size()];
          ByteBuffer bb = ByteBuffer.wrap(data);
          fc.read(bb); 

          System.out.println("Uncompressed Byte Array Size: "+data.length);

          //Compress the byte array
          byte [] compressedData = ZipUtil.compressByteArray(data);
          System.out.println("Compressed Byte Array Size: "+compressedData.length);

          //uncompress the byte array
          byte [] uncompressedData = ZipUtil.uncompressByteArray(compressedData);

          //Print out the contents of the uncompressed byte array
          System.out.println("Uncompressed Data: " + new String(uncompressedData));
        } catch (Exception e) {
          System.err.println("An error occurred:"+e.toString());
        }
    }
}