記一次字符串壓縮操作
項目中遇到一個場景:需要將一批數據發送到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壓縮後數據,直接轉成字符串的話,會有很多不可見字符,這樣在傳輸過程中,通常會被服務端框架轉義,從而失真。
代碼僅作爲示例使用,實際業務編碼請注意檢查錯誤和異常等。