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

我使用适当的客户端/服务器消息格式,限制我可以通过网络发送的内容。 我无法发送序列化对象,我必须将消息中的数据存储为String。 我发送的数据是以逗号分隔的大值,我想在将数据作为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; } 

据我所知,您目前的做法是:

  1. 使用getBytes("UTF-8")将String转换为字节数组。
  2. 压缩字节数组
  3. 使用new String(bytes, ..., "UTF-8")将压缩字节数组转换为String。
  4. 传输压缩字符串
  5. 接收压缩字符串
  6. 使用getBytes("UTF-8")将压缩字符串转换为字节数组。
  7. 解压缩字节数组
  8. 使用new String(bytes, ..., "UTF-8")将解压缩的字节数组转换为String。

此方法的问题在于步骤3.压缩字节数组时,将创建一个字符序列,该字节序列可能不再是有效的UTF-8。 结果将是步骤3中的例外。

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

笔记:

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

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

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

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

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

 catch (UnsupportedEncodingException e) { //TODO } 

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

如果我在格式错误的String上运行你的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) 

充气机/平衡器不是压缩绳的解决方案。 我认为GZIPInputString和GZIPOutputString是压缩字符串的合适工具

我遇到了类似的问题,它通过base64解码输入来解决。
即代替

 data.getBytes(UTF8_CHARSET) 

我试过了

 Base64.decodeBase64(data) 

它工作。