记一次字符串压缩操作
项目中遇到一个场景:需要将一批数据发送到APP端,且实际应用场景中,对数据的长度有一定的限制,于是就需要用到字符串压缩。
APP端使用Java
,后端使用Golang
,使用gzip
压缩,同时涉及到了base64
编码,中文和西欧字符集转码。
过程描述
后端:
- 字符集转换 参考自:一个复杂的中文编码问题
- 压缩字符串
- 使用base64编码为可见字符
- 网络传输
APP端
- 接收网络响应
- base64解码,得到一个字节数组(压缩的)
- gzip读取压缩的字节流,解压缩
- 转码为中文
示例代码
所有示例代码可以在这里找到
- server端
func compress(s string) string {
//使用GBK字符集encode
gbk, err := simplifiedchinese.GBK.NewEncoder().Bytes([]byte(s))
if err != nil {
logrus.Error(err)
return ""
}
//转为ISO8859_1,也就是latin1字符集
latin1, err := charmap.ISO8859_1.NewDecoder().Bytes(gbk)
if err != nil {
return ""
}
//使用gzip压缩
var buf bytes.Buffer
zw := gzip.NewWriter(&buf)
_, err = zw.Write(latin1)
if err != nil {
logrus.Fatal(err)
}
if err := zw.Close(); err != nil {
logrus.Fatal(err)
}
//使用base64编码
encoded := base64.StdEncoding.EncodeToString(buf.Bytes())
fmt.Println(encoded)
return encoded
}
- APP端
private static String uncompress(String s) throws IOException {
//base64 decode
byte[] byteArray = Base64.getDecoder().decode(s);
ByteArrayInputStream bis = new ByteArrayInputStream(byteArray);
//gzip解压
GZIPInputStream gis = new GZIPInputStream(bis);
BufferedReader br = new BufferedReader(new InputStreamReader(gis, "UTF-8"));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
gis.close();
bis.close();
//使用latin1字符集获得bytes
byte[] latin1 = sb.toString().getBytes("ISO_8859_1");
//转换回GBK
return new String(latin1, "GBK");
}
使用base64编码,主要是因为经过gzip压缩后数据,直接转成字符串的话,会有很多不可见字符,这样在传输过程中,通常会被服务端框架转义,从而失真。
代码仅作为示例使用,实际业务编码请注意检查错误和异常等。