繁体   English   中英

在Java中解压缩GZip字符串

[英]Decompress GZip string in Java

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

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

我正在尝试使用:

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

但这只会引发异常:java.io.IOException:不是GZIP格式

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

如果要压缩字符串,则需要先将其转换为二进制 - 例如将OutputStreamWriter链接到压缩OutputStream (例如GZIPOutputStream

同样地读取数据,你可以使用一个InputStreamReader链接到一个解压InputStream (如GZIPInputStream )。

Reader轻松读取的一种方法是使用来自Guava的 CharStreams.toString(Readable)或类似的库。

理想情况下,您应该使用高级库来为您处理这些内容。 这样,无论何时发布新版本的HTTP,图书馆维护者都希望为您完成所有艰苦的工作,您只需要更新版本的库。

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

让我们假设您正在从TCP套接字读取HTTP响应作为字节流。 如果没有gzip编码,那么将整个响应放入String中就可以了。 但是,“ Content-Encoding:gzip ”标头的存在意味着响应主体(如您所述)将是二进制的。

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

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会产生“Not in GZIP format”错误,因此测试这些错误将有助于解决您的特定问题。

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

可能有帮助:

try (final GZIPInputStream gzipInput = new GZIPInputStream(new ByteArrayInputStream(compressedByteArray));
        final StringWriter stringWriter = new StringWriter()) {
        org.apache.commons.io.IOUtils.copy(gzipInput, stringWriter, "UTF_8");
        String decodedString = stringWriter.toString();
    } catch (IOException e) {
        throw new UncheckedIOException("Error while decompression!", e);
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM