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

6
以下代码基于java.util.zip.Deflater的javadocs示例。我唯一做的更改是创建了一个名为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);
    }
}

如果我在没有设置字典的情况下尝试解压相同的压缩字节,不会出现错误,但返回的结果为零字节。

使用Deflater / Inflater时,是否需要特别注意使用自定义字典?

1个回答

10

实际上在提问题的过程中我已经弄清楚了,但我还是觉得应该发布这个问题,以便其他人也可以从我的困境中受益。

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

修改后的代码如下:

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);
    }
}

从 API 设计角度来看,这似乎非常反直觉和笨拙,如果有更好的替代方案,请启示我。


5
needsDictionary()之所以存在是因为zlib格式允许在同一应用程序中使用不同的字典,并在文件头中指定字典的Adler32校验和。为了读取此标头(并允许解压缩方面的应用程序选择正确的字典),需要首先调用inflate - Paŭlo Ebermann
当我这样做时,我需要在inflate()之前设置字典,这很好奇地说。因此,在你的例子中有些不对劲... - Chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接