在Java中压缩用于客户端/服务器传输的字符串

时间:2009-09-12 02:19:37

标签: java string compression

我使用适当的客户端/服务器消息格式,限制我可以通过网络发送的内容。我无法发送序列化对象,我必须将消息中的数据存储为String。我发送的数据是以逗号分隔的大值,我想在将数据打包成消息之前压缩数据。

我试图使用Deflater / Inflater来实现这一目标,但是在某个地方我遇到了困难。

我使用以下两种方法进行放气/充气。但是,将compressString()方法的结果传递给decompressStringMethod()会返回null结果。

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 个答案:

答案 0 :(得分:11)

据我所知,您当前的方法是:

  1. 使用getBytes("UTF-8")将字符串转换为字节数组。
  2. 压缩字节数组
  3. 使用new String(bytes, ..., "UTF-8")将压缩字节数组转换为String。
  4. 传输压缩字符串
  5. 接收压缩字符串
  6. 使用getBytes("UTF-8")将压缩字符串转换为字节数组。
  7. 解压缩字节数组
  8. 使用new String(bytes, ..., "UTF-8")将解压缩的字节数组转换为String。
  9. 此方法的问题在于步骤3.压缩字节数组时,会创建一个字符序列,这些字节可能不再是有效的UTF-8。结果将是步骤3中的例外。

    解决方案是使用像Base64这样的“字节到字符”编码方案将压缩字节转换为可传输的字符串。换句话说,用调用Base64编码函数替换步骤3,用调用Base64解码函数替换步骤6。

    注意:

    1. 对于小弦,压缩和 编码很可能实际上 增加传输字符串的大小。
    2. 如果要将压缩的字符串合并到URL中,您可能希望为Base64选择不同的编码,以避免需要进行URL转义的字符。
    3. 根据您传输的数据的性质,您可能会发现特定于域的压缩比通用压缩效果更好。考虑在创建以逗号分隔的字符串之前压缩数据。考虑以逗号分隔的字符串的替代方法。

答案 1 :(得分:1)

问题是您将压缩字节转换为字符串,这会破坏数据。您的compressStringdecompressString应该适用于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;
}

答案 2 :(得分:0)

TO ME:自己编写压缩算法很困难但是将二进制写入字符串则不行。所以,如果我是你,我将正常序列化对象并使用压缩(由ZipFile提供)压缩它,然后使用类似Base64 Encode/Decode的内容转换为字符串。

我实际上有BASE64 ENCODE / DECODE功能。如果你想我可以在这里发布。

答案 3 :(得分:0)

如果你有一段似乎在默默地失败的代码,也许你不应该抓住并吞下例外:

catch (UnsupportedEncodingException e) {
    //TODO
}

但解压缩返回null的真正原因是因为您的异常处理没有指定在捕获异常时如何处理result - result保留为null。您是否正在检查输出以查看是否发生了任何异常?

如果我在格式错误的字符串上运行你的decompress(),那么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)

答案 4 :(得分:0)

Inflator / Deflator不是压缩字符串的解决方案。 我认为GZIPInputString和GZIPOutputString是压缩字符串的合适工具

答案 5 :(得分:0)

我遇到了类似的问题,这是由base64解码输入解决的 而不是

data.getBytes(UTF8_CHARSET)  

我试过

Base64.decodeBase64(data)  

它有效。