Java - 压缩输出字节数组的大小

5
使用java.util.zip.Deflater的deflate方法时,需要提供一个byte[]作为参数,这个byte[]应该初始化多大呢?我读过,没有保证压缩后的数据一定比未压缩的数据更小。有没有输入量的特定百分比可以参考? 目前,我将其初始化为输入量的两倍。
2个回答

8

在调用deflate之后,调用finished来查看它是否还有更多的输出。例如:

byte[] buffer = new byte[BUFFER_SIZE];
while (!deflater.finished()) {
  int n = deflater.deflate(buffer);
  // deal with the n bytes in out here
}

如果您只想在内存中收集所有字节,可以使用ByteArrayOutputStream。例如:
byte[] buffer = new byte[BUFFER_SIZE];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (!deflater.finished()) {
  int n = deflater.deflate(buffer);
  baos.write(buffer, 0, n);
}
return baos.toByteArray();

3
如果你想得到一个巨大的字节数组,可以在循环外创建一个ByteArrayOutputStream,然后每次迭代时使用bos.append(out, 0, n)将结果附加到其中。 - Adam Batkin
9
谢谢您的问题。不过我还不太明白... 我需要多次调用deflate()直到整个输入都被压缩吗?BUFFER_SIZE应该设置为多少呢?有没有教程之类的东西可以解释一下这个问题?谢谢 - Clox
1
我猜可能是某种竞态条件导致的,因为这正是我发布的第二个示例片段所做的。 :-) - Laurence Gonsalves
1
是的:您需要多次调用deflate(),直到整个输入都被压缩。上面的代码就是这样做的。BUFFER_SIZE实际上是一个“调优参数”。只要它是正整数,代码就可以工作,但性能将取决于您设置的值。我可能会将其设置为4096(4k),然后只有在性能受到影响时才进行微调。 - Laurence Gonsalves
2
我不知道有没有关于这个的教程,但你可能会发现GZIPOutputStream的源代码很有启示性。它在内部使用Deflater。它恰好使用了默认的缓冲区大小为512,但是你可以在创建GZIPOutputStream时选择缓冲区大小。如果你有JDK源代码,你可以在那里查看GZIPOutputStream。如果没有,你可以在这个页面上看到它们:http://kickjava.com/src/java/util/zip/GZIPOutputStream.java.htm - Laurence Gonsalves
显示剩余6条评论

7

为什么Java把类拼错成了“deflater”?正确的单词应该是“deflator”。唉!抱歉,我得发泄一下。

正如所述,预期的使用方法是不断调用deflate直到从压缩中获取所有输出。然而,如果你真的想在一个调用中完成,那么deflate可以扩展数据的数量有一个上限。在zlib中有一个函数,Java不幸没有提供,叫做deflateBound(),它提供了这个上限。你可以使用该函数提供的保守上限,相关行在此处复制:

complen = sourceLen +
          ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;

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