Подтвердить что ты не робот

Декомпрессия строки GZip в Java

Я могу найти множество функций, которые позволят вам распаковать файл GZip, но как я могу распаковать строку GZip?

Я пытаюсь разобрать HTTP-ответ, когда тело ответа сжимается с помощью GZip. Однако весь ответ просто сохраняется в строке, поэтому часть строки содержит двоичные символы.

Я пытаюсь использовать:

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

Но это просто исключает исключение: java.io.IOException: не в формате GZIP

4b9b3361

Ответ 1

Нет такой вещи, как строка GZip. GZip является двоичным, строки - это текст.

Если вы хотите сжать строку, вам нужно сначала преобразовать ее в двоичный файл. с OutputStreamWriter прикованным к сжатию OutputStream (например, GZIPOutputStream)

Аналогично, чтобы прочитать данные, вы можете использовать InputStreamReader прикованный к распаковке InputStream (например, GZIPInputStream).

Одним из способов легкого чтения из Reader является использование CharStreams.toString(Readable) из Guava или аналогичную библиотеку.

Ответ 2

В идеале вы должны использовать библиотеку высокого уровня для обработки этого материала для вас. Таким образом, всякий раз, когда выпущена новая версия HTTP, разработчик библиотеки, надеюсь, сделает всю тяжелую работу для вас, и вам просто нужна обновленная версия библиотеки.

В стороне, это хорошее упражнение, чтобы попробовать сделать это самостоятельно.

Предположим, вы читаете HTTP-ответ как поток байтов из сокета TCP. Если бы не было кодирования 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();
                    }
                }

Ошибка "Not in GZIP format" создается GZIPInputStream, если первые 3 байта не соответствуют значениям заголовка магического GZIP, поэтому тестирование для них поможет решить вашу конкретную проблему.

Существует также контрольная сумма CRC в формате GZIP, однако, если это отсутствует или неверно, вы должны увидеть другую ошибку.

Ответ 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);
    }