Deflater.setLevel()有效吗?

时间:2013-07-13 17:00:41

标签: java deflate

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

以上对我来说没问题(Java 7),但是当我取消注释compresser.setLevel()行时,它会中断(deflate()返回0个字节)。除了DEFAULT之外,任何压缩级别都会发生相同的情况。更具体地说,它只是"工作" (而且,它是无害的)当级别集与构造函数中设置的(显式或隐式,如此处)相同时 - 也就是说,它只能在它无用时使用。

请参阅Ideone上的示例。

This question指向同一个问题,并且接受的答案基本上说:不要使用setter设置级别,在构造函数中执行。 IMO - 为什么setLevel()存在,这远非令人满意?它坏了还是我们错过了什么?

2 个答案:

答案 0 :(得分:5)

我挖了一下JDK源代码。它确实确定了水平。如果您使用setLevel()compresser.deflate(new byte[0]);,则可以使用。

正在发生的事情是deflate()之后setLevel()的第一次调用会看到级别已更改,并调用zlib的deflateParams()函数来更改它。然后,deflateParams()将压缩可用数据,但是您要求finish()的事实不会传递。然后,JDK实现不会使用deflate()调用Z_FINISH。结果,您提供的数据被发送以进行压缩,压缩器会累积数据,但它不会发出压缩块,因为它没有被要求完成。所以什么都没得到。

您需要在deflate()之后调用setLevel()来实际设置关卡。然后将使用新级别压缩后续数据。

请务必注意,deflate()之后的第一个setLevel()来电前提供的数据将使用压缩级别进行压缩。只有deflate()次呼叫后提供的数据才会使用新级别。因此,如果在您的示例中,您只是在最后一个之后执行了另一个deflate(),它将应用finish()并且您将获得压缩数据,但它将使用默认压缩级别。

答案 1 :(得分:3)

我怀疑这是一个错误。

如果查看source code,您会发现只有在构造函数中它们才会调用实际设置压缩级别的本机方法init。似乎必须在发生任何本机init调用之前设置压缩级别.ie在创建Deflater对象之前。

setLevel(int)只是表面上设置对象的级别。没有调用本机库。