Zlib compression Using Deflate and Inflate classes in Java

Ashish Agarwal picture Ashish Agarwal · May 30, 2011 · Viewed 43.1k times · Source

I want trying to use the Deflate and Inflate classes in java.util.zip for zlib compression.

I am able to compress the code using Deflate, but while decompressing, I am having this error -

Exception in thread "main" java.util.zip.DataFormatException: unknown compression method
    at java.util.zip.Inflater.inflateBytes(Native Method)
    at java.util.zip.Inflater.inflate(Inflater.java:238)
    at java.util.zip.Inflater.inflate(Inflater.java:256)
    at zlibCompression.main(zlibCompression.java:53)

Here is my code so far -

import java.util.zip.*;
import java.io.*;

public class zlibCompression {

    /**
     * @param args
     */
    public static void main(String[] args) throws IOException, DataFormatException {
        // TODO Auto-generated method stub

        String fname = "book1";
        FileReader infile = new FileReader(fname);
        BufferedReader in = new BufferedReader(infile);

        FileOutputStream out = new FileOutputStream("book1out.dfl");
        //BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename));

        Deflater compress = new Deflater();
        Inflater decompress = new Inflater();

        String readFile = in.readLine();
        byte[] bx = readFile.getBytes();

        while(readFile!=null){
            byte[] input = readFile.getBytes();
            byte[] compressedData = new byte[1024];
            compress.setInput(input);
            compress.finish();
            int compressLength = compress.deflate(compressedData, 0, compressedData.length);
            //System.out.println(compressedData);
            out.write(compressedData, 0, compressLength);
            readFile = in.readLine();
        }

        File abc = new File("book1out.dfl");
        InputStream is = new FileInputStream("book1out.dfl");

        InflaterInputStream infl = new InflaterInputStream(new FileInputStream("book1out.dfl"), new Inflater());
        FileOutputStream outFile = new FileOutputStream("decompressed.txt");

        byte[] b = new byte[1024];
        while(true){

            int a = infl.read(b,0,1024);
            if(a==0)
                break;

            decompress.setInput(b);
            byte[] fresult = new byte[1024];
            //decompress.in
            int resLength = decompress.inflate(fresult);
            //outFile.write(b,0,1);
            //String outt = new String(fresult, 0, resLength);
            //System.out.println(outt);
        }

        System.out.println("complete");

    }
}

Answer

Paŭlo Ebermann picture Paŭlo Ebermann · Jun 16, 2011

What are you trying to do here? You use an InflaterInputStream, which decompresses your data, and then you try to pass this decompressed data again to an Inflater? Use either one of them, but not both.

This is what is causing your exception here.

In addition to this, there are quite some minor errors, like these mentioned by bestsss:

  • You finish the compression in the loop - after finishing, no more data can be added.
  • You don't check how much output the deflate process produces. If you have long lines, it could be more than 1024 bytes.
  • You set input to the Inflater without setting the length a, too.

Some more which I found:

  • You don't close your FileOutputStream after writing (and before reading from the same file).
  • You use readLine() to read a line of text, but then you don't add the line break again, which means in your decompressed file won't be any line breaks.
  • You convert from bytes to string and to bytes again without any need.
  • You create variables which you don't use later on.

I won't try to correct your program. Here is a simple one which does what I think you want, using DeflaterOutputStream and InflaterInputStream. (You could also use JZlib's ZInputStream and ZOutputStream instead.)

import java.util.zip.*;
import java.io.*;

/**
 * Example program to demonstrate how to use zlib compression with
 * Java.
 * Inspired by http://stackoverflow.com/q/6173920/600500.
 */
public class ZlibCompression {

    /**
     * Compresses a file with zlib compression.
     */
    public static void compressFile(File raw, File compressed)
        throws IOException
    {
        InputStream in = new FileInputStream(raw);
        OutputStream out =
            new DeflaterOutputStream(new FileOutputStream(compressed));
        shovelInToOut(in, out);
        in.close();
        out.close();
    }

    /**
     * Decompresses a zlib compressed file.
     */
    public static void decompressFile(File compressed, File raw)
        throws IOException
    {
        InputStream in =
            new InflaterInputStream(new FileInputStream(compressed));
        OutputStream out = new FileOutputStream(raw);
        shovelInToOut(in, out);
        in.close();
        out.close();
    }

    /**
     * Shovels all data from an input stream to an output stream.
     */
    private static void shovelInToOut(InputStream in, OutputStream out)
        throws IOException
    {
        byte[] buffer = new byte[1000];
        int len;
        while((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }
    }


    /**
     * Main method to test it all.
     */
    public static void main(String[] args) throws IOException, DataFormatException {
        File compressed = new File("book1out.dfl");
        compressFile(new File("book1"), compressed);
        decompressFile(compressed, new File("decompressed.txt"));
    }
}

For more efficiency, it might be useful to wrap the file streams with buffered streams. If this is performance critical, measure it.