我的应用程序需要一个编码为字节数组的双精度列表,其中的小端编码已被zlib压缩,然后编码为基数64.我编写了一个线束来测试我的编码,但这并不起作用。我能够取得进步。
然而,我注意到当我尝试解压缩到固定大小的缓冲区时,我能够得到输入,使得解压缩的字节数组的大小小于原始字节数组,这显然不是“#”。对。与此同时,列表中的最后一个双重消失。在大多数输入上,固定缓冲区大小再现输入。有谁知道为什么会这样?我猜测错误是我编码数据的方式,但我无法弄清楚出了什么问题。
当我尝试使用ByteArrayOutputStream处理任意大小的可变长度输出时(这对于代码的真实版本很重要,因为我不能保证最大大小限制),Inflater的膨胀方法不断返回0.我查阅了文档,它说这意味着它需要更多数据。由于没有更多的数据,我再次怀疑我的编码,并猜测它是导致先前解释的行为的相同问题。
在我的代码中,我提供了一个数据示例,该数据在固定缓冲区大小下运行良好,以及对固定缓冲区不起作用的数据。这两个数据集都会导致我解释的变量缓冲区大小错误。
关于我做错了什么的线索?非常感谢。
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import org.apache.commons.codec.binary.Base64;
public class BinaryReaderWriter {
public static void main(String [ ] args) throws UnsupportedEncodingException, DataFormatException
{
// this input will break the fixed buffer method
//double[] centroids = {123.1212234143345453223123123, 28464632322456781.23, 3123121.0};
// this input will break the fixed buffer method
double[] centroids = {123.1212234143345453223123123, 28464632322456781.23, 31.0};
BinaryReaderWriter brw = new BinaryReaderWriter();
String output = brw.compressCentroids(centroids);
brw.decompressCentroids(output);
}
void decompressCentroids(String encoded) throws DataFormatException{
byte[] binArray = Base64.decodeBase64(encoded);
// This block of code is the fixed buffer version
//
System.out.println("binArray length " + binArray.length);
Inflater deCompressor = new Inflater();
deCompressor.setInput(binArray, 0, binArray.length);
byte[] decompressed = new byte[1024];
int decompressedLength = deCompressor.inflate(decompressed);
deCompressor.end();
System.out.println("decompressedLength = " + decompressedLength);
byte[] decompressedData = new byte[decompressedLength];
for(int i=0;i<decompressedLength;i++){
decompressedData[i] = decompressed[i];
}
/*
// This block of code is the variable buffer version
//
ByteArrayOutputStream bos = new ByteArrayOutputStream(binArray.length);
Inflater deCompressor = new Inflater();
deCompressor.setInput(binArray, 0, binArray.length);
byte[] decompressed = new byte[1024];
while (!deCompressor.finished()) {
int decompressedLength = deCompressor.inflate(decompressed);
bos.write(decompressed, 0, decompressedLength);
}
deCompressor.end();
byte[] decompressedData = bos.toByteArray();
*/
ByteBuffer bb = ByteBuffer.wrap(decompressedData);
bb.order(ByteOrder.LITTLE_ENDIAN);
System.out.println("decompressedData length = " + decompressedData.length);
double[] doubleValues = new double[decompressedData.length / 8];
for (int i = 0; i< doubleValues.length; i++){
doubleValues[i] = bb.getDouble(i * 8);
}
for(double dbl : doubleValues){
System.out.println(dbl);
}
}
String compressCentroids(double[] centroids){
byte[] cinput = new byte[centroids.length * 8];
ByteBuffer buf = ByteBuffer.wrap(cinput);
buf.order(ByteOrder.LITTLE_ENDIAN);
for (double cent : centroids){
buf.putDouble(cent);
}
byte[] input = buf.array();
System.out.println("raw length = " + input.length);
byte[] output = new byte[input.length];
Deflater compresser = new Deflater();
compresser.setInput(input);
compresser.finish();
int compressedLength = compresser.deflate(output);
compresser.end();
System.out.println("Compressed length = " + compressedLength);
byte[] compressed = new byte[compressedLength];
for(int i = 0; i < compressedLength; i++){
compressed[i] = output[i];
}
String decrypted = Base64.encodeBase64String(compressed);
return decrypted;
}
}
答案 0 :(得分:1)
压缩数据时我们真正做的是re-encoding
来增加数据中的熵。在重新编码过程中,我们必须添加元数据来告诉我们如何对数据进行编码,以便将其转换回以前的数据。
只有meta data size is less
比我们reencoding the data
节省的空间,压缩才会成功。
考虑Huffman encoding
:
Huffman是一种简单的编码方案,我们用fixed width character set
和charset长度表替换variable width character set
。由于显而易见的原因,长度表大小将大于0。如果所有字符的分布几乎相等,我们将无法保存任何空间。因此,我们的压缩数据最终会比我们的未压缩数据更大。