Java Deflater.setLevel()工作吗?

Java Deflater.setLevel()工作吗?,java,deflate,Java,Deflate,对我来说没有预期的效果 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")); compress

对我来说没有预期的效果

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));
}
上面的代码对我来说没有问题(Java7),但是当我取消注释
compresser.setLevel()
行时,它会中断(
deflate()
返回0字节)。除了
默认值
之外,任何压缩级别都会发生同样的情况。更具体地说,它只有在级别集与构造函数中设置的级别集相同时才“起作用”(更确切地说,它是无害的),也就是说,它只能在无用时使用

请参阅上的示例


指向同一个问题,公认的答案基本上是:不要用setter设置级别,而是在构造函数中设置。IMO远远不能令人满意-为什么存在
setLevel()
?它坏了还是我们丢失了什么?

我怀疑这是一个bug

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


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

我对JDK源代码进行了一些深入研究。它确实设定了水平。如果按照
setLevel()
使用
compresser.deflate(新字节[0]),则它将工作


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

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


需要注意的是,在
setLevel()
之后的第一次
deflate()
调用之前提供的数据将使用旧的压缩级别进行压缩。只有在调用
deflate()
之后提供的数据才会使用新级别。因此,如果在您的示例中,您只是在上一个之后执行另一个
deflate()
,它将应用
finish()
,您将获得压缩数据,但它将使用默认的压缩级别。

这似乎是
Deflater
API中的一个错误。。。阅读javadoc时,根本不清楚
.finish()
到底做了什么。上一个答案中提出的解决方法有效吗?如果
setLevel()
是一个伪装的NOP(在…)就已经够糟糕了,但更糟糕的是,它似乎破坏了解压。下一次调用
deflate()
设置了级别。“您请求完成()的事实没有传递”这将是一个错误,不是吗?我会说是的。尤其是因为我看不到这种行为在哪里被记录下来。