java.util.zip.ZipException: Not in GZIP format异常的产生原因及解决方法

  • Post author:
  • Post category:java


问题:在使用

GZIP压缩和解压缩

时可能会出现java.util.zip.ZipException: Not in GZIP format异常。

原因:在使用GZIP进行压缩时,创建GZIPOutputStream对象时,会调用一个writeHeader方法,此方法会在输出流中写入GZIP的头信息。代码如下:

private void writeHeader() throws IOException {
        out.write(new byte[] {
                      (byte) GZIP_MAGIC,        // Magic number (short)
                      (byte)(GZIP_MAGIC >> 8),  // Magic number (short)
                      Deflater.DEFLATED,        // Compression method (CM)
                      0,                        // Flags (FLG)
                      0,                        // Modification time MTIME (int)
                      0,                        // Modification time MTIME (int)
                      0,                        // Modification time MTIME (int)
                      0,                        // Modification time MTIME (int)
                      0,                        // Extra flags (XFLG)
                      0                         // Operating system (OS)
                  });
    }

头部信息中前两个字节用于存储魔数,GZIP_MAGIC值为35615,第一个字节存储低位,第二个字节存储高位。在解压缩时GZIPInputStream会调用readheader读取头信息。代码如下:

    private int readHeader(InputStream this_in) throws IOException {
        CheckedInputStream in = new CheckedInputStream(this_in, crc);
        crc.reset();
        // Check header magic
        if (readUShort(in) != GZIP_MAGIC) {
            throw new ZipException("Not in GZIP format");
        }
        // Check compression method
        if (readUByte(in) != 8) {
            throw new ZipException("Unsupported compression method");
        }
        // Read flags
        int flg = readUByte(in);
        // Skip MTIME, XFL, and OS fields
        skipBytes(in, 6);
        int n = 2 + 2 + 6;
        // Skip optional extra field
        if ((flg & FEXTRA) == FEXTRA) {
            int m = readUShort(in);
            skipBytes(in, m);
            n += m + 2;
        }
        // Skip optional file name
        if ((flg & FNAME) == FNAME) {
            do {
                n++;
            } while (readUByte(in) != 0);
        }
        // Skip optional file comment
        if ((flg & FCOMMENT) == FCOMMENT) {
            do {
                n++;
            } while (readUByte(in) != 0);
        }
        // Check optional header CRC
        if ((flg & FHCRC) == FHCRC) {
            int v = (int)crc.getValue() & 0xffff;
            if (readUShort(in) != v) {
                throw new ZipException("Corrupt GZIP header");
            }
            n += 2;
        }
        crc.reset();
        return n;
    }

GZIPInputStream首先通过readUShort读取前两个字节然后与魔数进行比较,如果相同表示当前字节数组为GZIP格式的字节数组,如果不相同则表示当前字节数组不是GZIP格式的数组于是会抛出异常java.util.zip.ZipException: Not in GZIP format。

结论:在使用GZIP进行压缩和解压时,如果压缩后的

字节数组在传输过程中发生改变

就会导致此异常的发生,所以如果不是直接传输压缩后的字节数组而是字符串时,在转换为字符串时,一定要使用ISO-8859-1这样的单字节编码,否则在将字符串转换为字节数组时会导致节数组产生变化,从而产生该异常。



版权声明:本文为asty9000原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。