Распаковка GZIPInputStream не работала нормально для сжатых данных длиной более 532 байт.

Я создал сжатие и распаковку с помощью gZipInputStream в java. Он отлично работает для небольшого объема данных, но если длина данных после сжатия становится больше 532, моя распаковка не работает нормально.

Спасибо, Бапи.


person Deepak    schedule 09.05.2009    source источник


Ответы (3)


Чтобы повторить то, что сказали другие:

  • Часто бывает так, что str.length() != str.getBytes().length(). Многие операционные системы используют кодировку переменной длины (например, UTF-8, UTF-16 или Windows-949).
  • Используйте OutputStream.close методы, обеспечивающие правильную запись всех данных.
  • Используйте возвращаемое значение InputStream.read, чтобы увидеть, сколько байтов было прочитано. Нет гарантии, что все данные будут прочитаны за один раз.
  • Будьте осторожны при использовании Строковый класс для кодирования/декодирования.

Методы сжатия/распаковки строк

  private static byte[] compress(String str, Charset charset) {
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    try {
      OutputStream deflater = new GZIPOutputStream(buffer);
      deflater.write(str.getBytes(charset));
      deflater.close();
    } catch (IOException e) {
      throw new IllegalStateException(e);
    }
    return buffer.toByteArray();
  }

  private static String decompress(byte[] data,
      Charset charset) {
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    ByteArrayInputStream in = new ByteArrayInputStream(data);
    try {
      InputStream inflater = new GZIPInputStream(in);
      byte[] bbuf = new byte[256];
      while (true) {
        int r = inflater.read(bbuf);
        if (r < 0) {
          break;
        }
        buffer.write(bbuf, 0, r);
      }
    } catch (IOException e) {
      throw new IllegalStateException(e);
    }
    return new String(buffer.toByteArray(), charset);
  }

  public static void main(String[] args) throws IOException {
    StringBuilder sb = new StringBuilder();
    while (sb.length() < 10000) {
      sb.append("write the data here \u00A3");
    }
    String str = sb.toString();
    Charset utf8 = Charset.forName("UTF-8");
    byte[] compressed = compress(str, utf8);

    System.out.println("String len=" + str.length());
    System.out.println("Encoded len="
        + str.getBytes(utf8).length);
    System.out.println("Compressed len="
        + compressed.length);

    String decompressed = decompress(compressed, utf8);
    System.out.println(decompressed.equals(str));
  }

(Обратите внимание: поскольку это потоки в памяти, я не строгий подход к их открытию и закрытию.)

person McDowell    schedule 09.05.2009

Я бы посоветовал вам использовать gCompress.close(), а не finish();

Я также предлагаю вам не полагаться на то, что str.length() будет достаточно длинным для чтения. Существует риск, что данные могут быть длиннее, поэтому строка будет усечена.

Вы также игнорируете возвращаемое значение read(). read() гарантированно будет читать() только один байт и вряд ли будет читать ровно байты данных str.length() , поэтому у вас, вероятно, будет много завершающих нулевых байтов \0. Вместо этого вы можете ожидать прочитать str.getBytes().length()

person Peter Lawrey    schedule 09.05.2009
comment
Почти в каждой строке есть ошибка — это прекрасный пример того, как НЕ достигать конечной цели. - person mP.; 09.05.2009

Для меня это похоже на проблему с кодировкой/декодированием символов. Следует использовать Readers/Writers для записи строк, например. String.getBytes(). Использование конструкций String(new byte[]) не является правильным способом..

Вы действительно должны использовать цикл для чтения и проверки возвращаемого значения bytes read value, чтобы убедиться, что все считано обратно!

person mP.    schedule 09.05.2009