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()
设置了级别。“您请求完成()的事实没有传递”这将是一个错误,不是吗?我会说是的。尤其是因为我看不到这种行为在哪里被记录下来。