在 Java 中解压缩 GZip 字符串

2022-09-03 14:41:31

我可以找到很多函数可以让你解压缩GZip文件,但是我如何解压缩GZip字符串?

我正在尝试解析一个HTTP响应,其中响应正文是用GZip压缩的。但是,整个响应只是存储在字符串中,因此字符串的一部分包含二进制字符。

我正在尝试使用:

byte responseBodyBytes[] = responseBody.getBytes();
ByteArrayInputStream bais = new ByteArrayInputStream(responseBodyBytes); 
GZIPInputStream gzis = new GZIPInputStream(bais);

但这只是抛出一个异常:java.io.IOException:不是GZIP格式


答案 1

没有GZip字符串这样的东西。GZip 是二进制的,字符串是文本。

如果你想压缩一个字符串,你需要先将其转换为二进制文件 - 例如,链接到压缩(例如GZIPOutputStreamOutputStreamWriterOutputStream)

同样,要读取数据,您可以使用链接到解压缩(例如GZIPInputStream)。InputStreamReaderInputStream

从中轻松读取的一种方法是使用番石榴CharStreams.toString(可读)或类似的库。Reader


答案 2

理想情况下,您应该使用高级库来为您处理这些东西。这样,每当发布新版本的HTTP时,库维护者都希望为您完成所有艰苦的工作,您只需要更新版本的库。

除此之外,尝试自己做是一个很好的练习。

假设您正在从 TCP 套接字以字节流的形式读取 HTTP 响应。如果没有 gzip 编码,则将整个响应放入 String 中可能会起作用。但是,“内容编码:gzip”标头的存在意味着响应正文(如您所见)是二进制的。

您可以将响应正文的开头标识为字符串序列“\r\n\r\n”第一次出现之后的第一个字节(或0x0d、0x0a、0x0d 0x0a 4 个字节)。

gzip 编码有一个特殊的标头,您应该为此测试前 3 个正文字节:

                byte[] buf;  // from the HTTP Response stream
                // ... insert code here to populate buf from HTTP Response stream
                // ...
                int bodyLen = 1234;  // populate this value from 'Content-length' header
                int bodyStart = 123; // index of byte buffer where body starts
                if (bodyLen > 4 && buf[bodyStart] == 0x1f && buf[bodyStart + 1] == (byte) 0x8b && buf[bodyStart + 2] == 0x08) {
                    // gzip compressed body
                    ByteArrayInputStream bais = new ByteArrayInputStream(buf);
                    if (bodyStart > 0) bais.skip(bodyStart);

                    // Decompress the bytes
                    byte[] decompressedBytes = new byte[bodyLen * 4];
                    int decompressedDataLength = 0;
                    try {
                        // note: replace this try-catch with try-with-resources here where possible
                        GZIPInputStream gzis = new GZIPInputStream(bais);
                        decompressedDataLength = gzis.read(decompressedBytes);
                        gzis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

如果前 3 个字节与神奇的 GZIP 标头值不匹配,则 GZIPInputStream 会生成“不采用 GZIP 格式”错误,因此测试这些值将有助于解决您的特定问题。

GZIP格式中还有一个CRC校验和,但是如果缺少或不正确,您应该会看到不同的错误。


推荐