簡體   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