在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; }
据我所知,您目前的做法是:
- 使用
getBytes("UTF-8")
将String转换为字节数组。 - 压缩字节数组
- 使用
new String(bytes, ..., "UTF-8")
将压缩字节数组转换为String。 - 传输压缩字符串
- 接收压缩字符串
- 使用
getBytes("UTF-8")
将压缩字符串转换为字节数组。 - 解压缩字节数组
- 使用
new String(bytes, ..., "UTF-8")
将解压缩的字节数组转换为String。
此方法的问题在于步骤3.压缩字节数组时,将创建一个字符序列,该字节序列可能不再是有效的UTF-8。 结果将是步骤3中的例外。
解决方案是使用像Base64这样的“字节到字符”编码方案将压缩字节转换为可传输的字符串。 换句话说,用调用Base64编码函数代替步骤3,用调用Base64解码函数代替步骤6。
笔记:
- 对于小字符串,压缩和编码实际上可能会增加传输字符串的大小。
- 如果压缩的String将要合并到URL中,您可能希望为Base64选择不同的编码,以避免需要进行URL转义的字符。
- 根据您传输的数据的性质,您可能会发现特定于域的压缩比通用压缩更好。 考虑在创建以逗号分隔的字符串之前压缩数据。 考虑以逗号分隔的字符串的替代方法。
问题是您将压缩字节转换为字符串,这会破坏数据。 你的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; }
对我来说:自己编写压缩算法很困难但是将二进制写入字符串则不行。 所以,如果我是你,我将正常序列化对象并压缩拉链(由ZipFile提供)然后使用类似Base64 Encode / Decode的转换为字符串。
我实际上有BASE64 ENCODE / DECODEfunction。 如果你想我可以在这里发布。
如果你有一段似乎在默默地失败的代码,也许你不应该抓住并吞下例外:
catch (UnsupportedEncodingException e) { //TODO }
但是,解压缩返回null的真正原因是因为您的exception处理没有指定在捕获exception时如何处理result
– result
保留为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)
它工作。
- Java返回Object /修改对象(编码指南)
- ResultSetImpl.checkColumnBounds或ResultSetImpl.getStringInternal中偶尔出现NullPointerException
- GWT RequestBuilder – 跨站请求
- 如何遍历String
- 当从Java应用程序连接到Spark Standalone时,为什么抛出“无法调用已停止的SparkContext上的方法”?
- 再次访问IEEE-754双(64位浮点)与长(64位整数)
- 可能是两个类之间的递归Javagenerics
- 如何为Java提供任意字体文件?
- 如何在使用注释时声明Spring bean autowire-candidate =“false”?