Распаковать строку GZip в Java - PullRequest
       3

Распаковать строку GZip в Java

14 голосов
/ 02 сентября 2010

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

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

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

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

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

Ответы [ 2 ]

14 голосов
/ 02 сентября 2010

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

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

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

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

1 голос
/ 29 января 2018

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

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

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

Ошибка «Не в формате GZIP» генерируется GZIPInputStream, если первые 3 байта не соответствуют значениям магического заголовка GZIP, поэтому их проверка поможет решить вашу конкретную проблему.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...