将Java Deflater/Inflater与自定义字典一起使用会导致IllegalArgumentException

Mik*_*eck 6 java compression zip deflate

以下代码基于java.util.zip.Deflaterjavadocs中给出的示例.我所做的唯一更改是创建一个名为dict的字节数组,然后使用setDictionary(byte [])方法在Deflater和Inflater实例上设置字典.

我看到的问题是,当我用与Deflater完全相同的数组调用Inflater.setDictionary()时,我得到一个IllegalArgumentException.

这是有问题的代码:

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);
        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);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试放弃相同的压缩字节而不设置字典,我得到没有错误,但返回的结果是零字节.

为了使用Deflater/Inflater的自定义词典,我需要做些什么特别的事吗?

Mik*_*eck 8

我在制定问题的过程中确实想到了这一点,但我认为我应该发布这个问题,以便其他人可以从我的挣扎中受益.

事实证明,在设置输入之后但设置字典之前,您必须调用inflate()一次.返回的值将为0,然后对needsDictionary()的调用将返回true.之后,您可以设置字典并再次调用充气.

修订后的代码如下:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

从API设计的角度来看,这似乎非常直观和笨拙,所以如果有更好的选择,请告诉我.

  • `needsDictionary()`的原因是zlib格式允许在同一个应用程序中使用不同的字典,并在文件头中指示字典的Adler32校验和.要读取此标题(并允许解压缩方的应用程序选择正确的字典),需要首次调用`inflate`. (4认同)