微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Java.util.zip.DataFormatException:不正确的标头检查

如何解决Java.util.zip.DataFormatException:不正确的标头检查

第一次发帖,通常我会在其他线程中找到我要找的东西,但这次没有:

我使用 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,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

对于这堵文字墙我很抱歉,但此时我真的不知道是什么导致了这个问题。

解决方法

好的,这是解决方案:

我的假设是这个循环会将新的读取数据附加到它上次停止的字节数组中,这不是这种情况(它似乎在 2^16 个字节后停止读取,这就是为什么我不使用较小的数据包解决此问题)。

这是错误的

int readBytes = 0;
while (readBytes < compressedLength) {
    int newByteAmount = dataIn.read(compressedData); // focus here!
    readBytes += newByteAmount;
}

所以发生的事情是数据被正确读取但是输出数组正在覆盖自己!!这就是为什么我在开头看到错误的数据而在结尾看到一堆 00 00(因为它实际上从未到达数组的那部分)!

改用它解决了我的问题:

dataIn.readFully(compressedData);

让我担心的是我看到了很多代码的第一个变体。这是我在谷歌搜索时发现的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。