Сжатие строк для транспорта клиент / сервер в Java - PullRequest
1 голос
/ 12 сентября 2009

Я работаю с собственным форматом сообщений клиент / сервер, который ограничивает отправку по сети. Я не могу отправить сериализованный объект, я должен сохранить данные в сообщении в виде строки. Данные, которые я отправляю, представляют собой большие значения, разделенные запятыми, и я хочу сжать данные, прежде чем упаковать их в сообщение в виде строки.

Я пытался использовать Deflater / Inflater для достижения этой цели, но где-то вдоль линии я застреваю.

Я использую два метода ниже, чтобы спустить / надуть. Однако передача результата метода compressString () в метод deppressStringMethod () возвращает нулевой результат.

public String compressString(String data) {
  Deflater deflater = new Deflater();
  byte[] target = new byte[100];
  try {
   deflater.setInput(data.getBytes(UTF8_CHARSET));
   deflater.finish();
   int deflateLength = deflater.deflate(target);
   return new String(target);
  } catch (UnsupportedEncodingException e) {
   //TODO
  }

  return data;
 }

 public String decompressString(String data) {

  String result = null;
  try {
   byte[] input = data.getBytes();

   Inflater inflater = new Inflater();
   int inputLength = input.length;
   inflater.setInput(input, 0, inputLength);

   byte[] output = new byte[100];
   int resultLength = inflater.inflate(output);
   inflater.end();

   result = new String(output, 0, resultLength, UTF8_CHARSET);
  } catch (DataFormatException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (UnsupportedEncodingException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

  return result;
 }

Ответы [ 6 ]

11 голосов
/ 12 сентября 2009

Из того, что я могу сказать, ваш нынешний подход:

  1. Преобразовать строку в байтовый массив, используя getBytes("UTF-8").
  2. Сжать байтовый массив
  3. Преобразовать сжатый байтовый массив в строку, используя new String(bytes, ..., "UTF-8").
  4. Передача сжатой строки
  5. Получить сжатую строку
  6. Преобразовать сжатую строку в байтовый массив, используя getBytes("UTF-8").
  7. Распаковка байтового массива
  8. Преобразовать распакованный байтовый массив в строку, используя new String(bytes, ..., "UTF-8").

Проблема с этим подходом заключается в шаге 3. Когда вы сжимаете байтовый массив, вы создаете последовательность байтов, которая больше не может быть допустимой UTF-8. Результатом будет исключение на шаге 3.

Решение состоит в том, чтобы использовать схему кодирования "байты в символы", такую ​​как Base64, чтобы превратить сжатые байты в передаваемую строку. Другими словами, замените шаг 3 вызовом функции кодирования Base64, а шаг 6 вызовом функции декодирования Base64.

Примечания:

  1. Для небольших струн, сжатия и кодирование, вероятно, на самом деле увеличить размер передаваемой строки.
  2. Если сжатая строка будет включена в URL, вы можете выбрать другую кодировку, отличную от Base64, чтобы избежать символов, которые должны быть экранированы от URL.
  3. В зависимости от характера передаваемых данных, вы можете обнаружить, что специфичное для домена сжатие работает лучше, чем обычное. Рассмотрите возможность сжатия данных перед созданием строки через запятую. Рассмотрим альтернативы разделенным запятыми строкам.
1 голос
/ 12 сентября 2009

Проблема в том, что вы конвертируете сжатые байты в строку, которая разбивает данные. Ваши compressString и decompressString должны работать на byte[]

РЕДАКТИРОВАТЬ: Вот пересмотренная версия. Работает

EDIT2: И о base64. вы отправляете байты, а не строки. Вам не нужно base64.

public static void main(String[] args) {
    String input = "Test input";
    byte[] data = new byte[100];

    int len = compressString(input, data, data.length);

    String output = decompressString(data, len);

    if (!input.equals(output)) {
        System.out.println("Test failed");
    }

    System.out.println(input + " " + output);
}

public static int compressString(String data, byte[] output, int len) {
    Deflater deflater = new Deflater();
    deflater.setInput(data.getBytes(Charset.forName("utf-8")));
    deflater.finish();
    return deflater.deflate(output, 0, len);
}

public static String decompressString(byte[] input, int len) {

    String result = null;
    try {
        Inflater inflater = new Inflater();
        inflater.setInput(input, 0, len);

        byte[] output = new byte[100]; //todo may oveflow, find better solution
        int resultLength = inflater.inflate(output);
        inflater.end();

        result = new String(output, 0, resultLength, Charset.forName("utf-8"));
    } catch (DataFormatException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return result;
}
0 голосов
/ 02 апреля 2013

Я столкнулся с подобной проблемой, которая была решена с помощью base64, декодирующего ввод. т.е. вместо

data.getBytes(UTF8_CHARSET)  

я пытался

Base64.decodeBase64(data)  

и это сработало.

0 голосов
/ 20 декабря 2011

Inflator / Deflator не является решением для строки сжатия. Я думаю, что GZIPInputString и GZIPOutputString - подходящий инструмент для сжатия строки

0 голосов
/ 12 сентября 2009

Если у вас есть фрагмент кода, который, по-видимому, молча терпит неудачу, возможно, вам не следует перехватывать и глотать исключения:

catch (UnsupportedEncodingException e) {
    //TODO
}

Но настоящая причина, по которой при распаковке возвращается значение NULL, заключается в том, что ваша обработка исключений не указывает, что делать с result при обнаружении исключения - result остается равным NULL. Вы проверяете вывод, чтобы увидеть, если какие-либо исключения происходят?

Если я запускаю декомпрессию () для плохо отформатированной строки, Inflater выдает мне это DataFormatException:

java.util.zip.DataFormatException: incorrect header check
    at java.util.zip.Inflater.inflateBytes(Native Method)
    at java.util.zip.Inflater.inflate(Inflater.java:223)
    at java.util.zip.Inflater.inflate(Inflater.java:240)
0 голосов
/ 12 сентября 2009

TO ME: написать алгоритм сжатия самому сложно, но записать двоичный файл в строку - нет. Так что, если бы я был вами, я обычно сериализовал бы объект и сжал бы его со сжатием (как предусмотрено ZipFile), а затем преобразовал в строку, используя что-то вроде Base64 Encode / Decode .

У меня фактически есть функции BASE64 ENCODE / DECODE. Если хотите, я могу выложить это здесь.

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