Deflater.setLevel()对我来说不能正常工作.
static void test1() throws Exception {
byte[] output = new byte[20];
Deflater compresser = new Deflater();
// compresser.setLevel(Deflater.BEST_COMPRESSION);
compresser.setInput("blah".getBytes("UTF-8"));
compresser.finish();
int len = compresser.deflate(output);
System.out.println("len="+ len+ " " +Arrays.toString(output));
}
Run Code Online (Sandbox Code Playgroud)
上面的工作对我来说没问题(Java 7),但是当我取消注释该compresser.setLevel()
行时,它会中断(deflate()
返回0个字节).任何压缩级别都会发生同样的情况,除了DEFAULT
.更具体地说,当级别集与构造函数中设置的(显式或隐式,如此处)相同时,它只"工作"(相反,它是无害的) - 也就是说,它只能在它无用时才能使用.
请参阅Ideone上的示例.
这个问题指出了同样的问题,并且接受的答案基本上说:不要用setter设置级别,在构造函数中执行.远非令人满意,IMO - 为什么setLevel()
存在?它坏了还是我们错过了什么?
我挖了一下JDK源代码.它确实确定了水平.如果您遵循setLevel()
with compresser.deflate(new byte[0]);
,那么它将起作用.
发生的事情是,在看到级别改变deflate()
之后的第一次调用setLevel()
,并调用zlib的deflateParams()
函数来改变它. deflateParams()
然后将压缩可用数据,但是您要求的finish()
数据不会被传递.JDK实现则不会调用deflate()
带Z_FINISH
.结果,您提供的数据被发送以进行压缩,压缩器会累积数据,但它不会发出压缩块,因为它没有被要求完成.所以什么都没得到.
您需要在实际设置级别deflate()
后调用setLevel()
.然后将使用新级别压缩后续数据.
重要的是要注意,deflate()
在setLevel()
使用旧压缩级别压缩之后提供给第一次调用的数据.只有该deflate()
呼叫后提供的数据才会使用新级别.因此,如果在您的示例中,您只是deflate()
在最后一个之后执行另一个,它将应用finish()
,您将获得压缩数据,但它将使用默认压缩级别.