【问题标题】:Decompress GZip string in Java在 Java 中解压缩 GZip 字符串
【发布时间】:2011-04-07 00:15:33
【问题描述】:

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

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

我正在尝试使用:

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

但这只会引发异常:java.io.IOException: Not in GZIP format

【问题讨论】:

标签: java gzip


【解决方案1】:

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

如果你想压缩一个字符串,你需要先将它转换成二进制 - 例如将OutputStreamWriter 链接到压缩的OutputStream(例如GZIPOutputStream

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

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

【讨论】:

  • 我正在尝试解析 HTTP 响应,其中响应主体使用 GZip 压缩。但是,整个响应只是存储在一个字符串中,因此部分字符串包含二进制字符。你是说不能把这个“GZip 字符串”转成文本字符串?
  • @Matt:您不应该将响应存储在字符串中。如果它是二进制的,则根本不应该是文本,除非它是 base64。 “部分字符串包含二进制数据”的概念确实行不通。听起来你需要改变你的方法。
  • 响应最初显示为 byte[],所以这就是我可用的全部。我可以用这个吗?
  • @Jon Skeet 我现在遇到了同样的问题。您是否建议将响应存储在 byte[] 中?
  • @Amir:我不知道你想做什么,所以很难说。我建议您在新问题中加入更多背景信息。
【解决方案2】:

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

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

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

您可以将响应正文的开头标识为第一次出现的字符串序列“\r\n\r\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 会产生“不是 GZIP 格式”错误,因此测试这些将有助于解决您的特定问题。

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

【讨论】:

    【解决方案3】:

    这可能会有所帮助:

    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);
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-18
      • 2010-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多