Using Java Deflater/Inflater with custom dictionary causes IllegalArgumentException
The following code is based on the example given in the javadocs for java.util.zip.Deflater. The only changes I have made is to create a byte array called dict and then set the dictionary on both the Deflater and Inflater instances using the setDictionary(byte[]) method.
The problem I'm seeing is that when I call Inflater.setDictionary() with the exact same array as I used for the Deflater, I get an IllegalArgumentException.
Here is the code in question:
import java.util.zip.Deflater;
import java.util.zip.Inflater;
public class DeflateWithDictionary {
public static void main(String[] args) throws Exception {
String inputString = "blahblahblahblahblah??";
byte[] input = inputString.getBytes("UTF-8");
byte[] dict = "blah".getBytes("UTF-8");
// Compress the bytes
byte[] output = n开发者_JAVA百科ew byte[100];
Deflater compresser = new Deflater();
compresser.setInput(input);
compresser.setDictionary(dict);
compresser.finish();
int compressedDataLength = compresser.deflate(output);
// Decompress the bytes
Inflater decompresser = new Inflater();
decompresser.setInput(output, 0, compressedDataLength);
decompresser.setDictionary(dict); //IllegalArgumentExeption thrown here
byte[] result = new byte[100];
int resultLength = decompresser.inflate(result);
decompresser.end();
// Decode the bytes into a String
String outputString = new String(result, 0, resultLength, "UTF-8");
System.out.println("Decompressed String: " + outputString);
}
}
If I try deflating the same compressed bytes without setting the dictionary, I get no error but the result returned is zero bytes.
Is there anything special I need to do in order to use a custom dictionary with Deflater/Inflater?
I actually figured this out while formulating the question but thought I should post the question anyway so others might benefit from my struggles.
It turns out you have to call inflate() once after setting the input but before setting the dictionary. The value returned will be 0, and a call to needsDictionary() will then return true. After that you can set the dictionary and call inflate again.
The amended code is as follows:
import java.util.zip.Deflater;
import java.util.zip.Inflater;
public class DeflateWithDictionary {
public static void main(String[] args) throws Exception {
String inputString = "blahblahblahblahblah??";
byte[] input = inputString.getBytes("UTF-8");
byte[] dict = "blah".getBytes("UTF-8");
// Compress the bytes
byte[] output = new byte[100];
Deflater compresser = new Deflater();
compresser.setInput(input);
compresser.setDictionary(dict);
compresser.finish();
int compressedDataLength = compresser.deflate(output);
// Decompress the bytes
Inflater decompresser = new Inflater();
decompresser.setInput(output, 0, compressedDataLength);
byte[] result = new byte[100];
decompresser.inflate(result);
decompresser.setDictionary(dict);
int resultLength = decompresser.inflate(result);
decompresser.end();
// Decode the bytes into a String
String outputString = new String(result, 0, resultLength, "UTF-8");
System.out.println("Decompressed String: " + outputString);
}
}
This seems very counter intuitive and clunky from an API design perspective, so please enlighten me if there are any better alternatives.
精彩评论