我使用适当的客户端/服务器消息格式,限制我可以通过网络发送的内容。我无法发送序列化对象,我必须将消息中的数据存储为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;
}
答案 0 :(得分:11)
据我所知,您当前的方法是:
getBytes("UTF-8")
将字符串转换为字节数组。new String(bytes, ..., "UTF-8")
将压缩字节数组转换为String。getBytes("UTF-8")
将压缩字符串转换为字节数组。new String(bytes, ..., "UTF-8")
将解压缩的字节数组转换为String。此方法的问题在于步骤3.压缩字节数组时,会创建一个字符序列,这些字节可能不再是有效的UTF-8。结果将是步骤3中的例外。
解决方案是使用像Base64这样的“字节到字符”编码方案将压缩字节转换为可传输的字符串。换句话说,用调用Base64编码函数替换步骤3,用调用Base64解码函数替换步骤6。
注意:
答案 1 :(得分:1)
问题是您将压缩字节转换为字符串,这会破坏数据。您的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;
}
答案 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)
它有效。