我的问题是 zip 压缩。我必须将文件分成几部分并并行压缩它们,然后以正确的顺序连接这些部分,并用一个文件保存为 zip 存档。拆分文件并将部分发送到主机不是问题 - 我使用的是 jpvm。我的问题是:如何拆分压缩?我尝试使用 java.util.zip.Deflater 压缩每个部分(结果是字节数组),然后将它们写入一个 ZipOutputStream,但这似乎不起作用 - 在保存到文件时它会压缩已经压缩的字节再一次。我是否必须使用 deflater 压缩每个部分,然后手动添加 zip 标头、一些校验和或类似的东西?Deflater 是否添加任何标题?感谢您的帮助,谢谢!
2 回答
您需要使用nowrap
选项Deflater
来生成没有标题或尾部的原始放气流。然后,您需要自己使用适当的 zip 标头和预告片来包装原始的 deflate 流。
要在多个处理器上创建单个 deflate 流,您需要能够使用zlibZ_SYNC_FLUSH
中的操作将压缩输出刷新到字节边界(对于不是最后一个片段的片段) 。(最后一块将正常完成。)然后可以简单地连接这些块。
Java 7(但不是 Java 6)文档通过方法的可选第四个参数支持这一点deflate()
。可以设置为SYNC_FLUSH
.
以这种方式分解数据会降低压缩率,因为每个块都不能从前一个块的历史中受益。这可以使用该setDictionary()
方法解决。向每个线程提供要压缩的数据以及它之前的 32K 字节未压缩数据。然后将 32K 与 一起使用setDictionary()
,然后使用deflate()
.
您可以在pigz中看到直接使用 zlib 在 C 中进行并行压缩的示例。
一旦你有你的放气流,你适当地包装它以使其成为一个 zip 文件。有关 zip 文件格式,请参阅appnote。您还需要计算未压缩数据的CRC-32才能填写这些字段。
不幸的是,你没有显示你的代码,所以我不能确定我完全理解你的意思。但是,据我了解您的问题,我可以向您推荐以下内容。
- 检查原始文件大小并决定块的大小。
- 开始读取文件,直到达到块大小。在阅读时使用
ZipOutputStream
. 创建带有后缀的文件,以便您稍后加入内容。后缀应该是运行索引。由于您想将一个文件存储在多个 zip 文件中,因此每个 zip 使用一个条目。 - 读取 zip 文件时,只需根据后缀(见前面)对它们进行排序并读取您唯一的条目,然后将字节
ZipInputSteam
从FileOutputStream
.
不幸的是,我不明白您的多个主机是什么意思。你的意思是你的文件太大了,以至于你同时在不同的机器上创建了每个 zip?如果这是正确的修改#2如下:在读取文件片段时将其内容发送到远程主机并ZipOutputStream
在那里使用。要从特定点读取文件,请使用InputStream.skip()
.