【发布时间】:2021-08-31 13:13:21
【问题描述】:
第一篇文章,通常我会在其他帖子中找到我要找的东西,但这次没有:
我正在使用 javas Deflater 和 Inflater 来压缩/解压缩我在正在处理的服务器和客户端应用程序之间发送的一些数据。
它适用于我 99% 的测试。然而,有一个特定的数据集在膨胀时从 inflater.inflate() 方法中抛出此异常:
DataFormatException: incorrect header check
与其他运行相比,数据没有什么特别之处。它只是一堆用逗号分隔的数字“编码”为字符串,然后完成 .getBytes() 。我唯一知道的是这次它有点大。在压缩 -> 解压缩步骤之间的任何地方都没有发生编码。
这是向客户端或服务器发送内容的代码。代码是共享的。
OutputStream outputStream = new DataOutputStream(socket.getOutputStream());
byte[] uncompressed = SOMEJSON.toString().getBytes();
int realLength = uncompressed.length;
// compress data
byte[] compressedData = ByteCompression.compress(uncompressed);
int compressedLength = compressedData.length;
outputStream.write(ByteBuffer.allocate(Integer.BYTES).putInt(compressedLength).array());
outputStream.write(ByteBuffer.allocate(Integer.BYTES).putInt(realLength).array());
outputStream.write(compressedData);
outputStream.flush();
这是接收数据(客户端或服务器)也共享的代码:
DataInputStream dataIn = new DataInputStream(socket.getInputStream());
int compressedLength = dataIn.readInt();
int realLength = dataIn.readInt();
errorhandling.info("Packet Reader", "Expecting " + compressedLength + " (" + realLength + ") bytes.");
byte[] compressedData = new byte[compressedLength];
int readBytes = 0;
while (readBytes < compressedLength) {
int newByteAmount = dataIn.read(compressedData);
// catch nothing being read or end of line
if (newByteAmount <= 0) {
break;
}
readBytes += newByteAmount;
}
if (readBytes != compressedLength) {
errorhandling.info("Packet Reader", "Read byte amount differs from expected bytes.");
return new ErrorPacket("Read byte amount differs from expected bytes.").create();
}
byte[] uncompressedData = ByteCompression.decompress(compressedData, realLength);
String packetData = new String(uncompressedData);
以下是压缩和解压缩 byteArray 的方法(您猜对了它的共享):
public static byte[] compress(byte[] uncompressed) {
Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
deflater.setInput(uncompressed);
deflater.finish();
byte[] compressed = new byte[uncompressed.length];
int compressedSize = 0;
while (!deflater.finished()) {
compressedSize += deflater.deflate(compressed);
}
deflater.end();
return Arrays.copyOfRange(compressed, 0, compressedSize);
}
public static byte[] decompress(byte[] compressed, int realLength) throws DataFormatException {
Inflater inflater = new Inflater(true);
inflater.setInput(compressed);
byte[] uncompressed = new byte[realLength];
while (!inflater.finished()) {
inflater.inflate(uncompressed); // throws DataFormatException: incorrect header check (but only super rarely)
}
inflater.end();
return uncompressed;
}
到目前为止,我已经尝试了不同的压缩级别,并弄乱了 Deflater 和 Inflater(所有组合)的“nowrap”选项:
// [...]
Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION, true);
// [...]
Inflater inflater = new Inflater(true);
但这只会导致这些异常(但同样只针对那个特定的数据集):
DataFormatException: invalid stored block lengths
DataFormatException: invalid distance code
我很抱歉这堵文字墙,但此时我真的不知道是什么导致了这个问题。
【问题讨论】:
-
您尝试扩充失败的数据的前几个字节是什么?
-
我现在发现输入的数据确实是错误的。在膨胀之前将数据写入来自客户端的文件表明标题不正确。有趣的是,如果我将数据保存到 SERVERSIDE 文件中,然后从同一个文件中读取 CLIENTSIDE,则通货膨胀工作得很好。因此,无论出于何种原因,数据在发送时都会在服务器和客户端之间被破坏。但仅适用于比其他工作正常的数据更大的数据。
-
损坏数据的第一个字节:43 12 56 19 个良好数据的第一个字节:78 DA 7D 9C
-
当您可以使用
DataOutputStream.writeInt()和DataInputStream.readInt()时,您正在使用所有的API 来发送和接收整数。不要把这个煮过头。同样,您可以摆脱大部分其他内容并使用Inflater/Deflater输入和输出流。
标签: java compression zlib deflate inflate