Распаковка GZIPInputStream не работала нормально для сжатых данных длиной более 532 байт - PullRequest
1 голос
/ 09 мая 2009

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

Спасибо Бапите

Ответы [ 3 ]

5 голосов
/ 09 мая 2009

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

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

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

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

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

2 голосов
/ 09 мая 2009

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

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

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

2 голосов
/ 09 мая 2009

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

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

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