本節摘要:本節主要簡單介紹對字符串的壓縮與解壓。
1.引言
最近在做項目中,平台提供一個http服務給其他系統調用,然后我接收到其他系統的json格式的報文后去解析,然后用拿到的數據去調用corba服務,我再把corba的返回值封裝完成json字符串返回給外部系統。遇到一個接口去調用corba服務,然后corba返回的數據經過封裝后字符串的長度達到7M左右,導致http客戶端無法正常的接收完所有的數據。你可能會說這個接口設計的不合理,為什么不增加查詢條件把查詢條件范圍縮小一點?但是,這個不是本節要討論的內容,主要是因為corba服務已經發布用了很久且不在此次項目改造范圍之內,再者這個corba服務已經上線用了N久,輕易的改變可能會導致未知的錯誤。簽於此,我想到可以把json格式的字符串給壓縮,然后客戶端再解壓。(一是字符串的壓縮比例比較的高,二是字符串的壓縮和解壓實現起來也比較簡單)。雖然,最后沒有用到字符串的壓縮和解壓的方式,而是修改客戶端(1.http客戶端進一步精確查詢條件 2.讀取返回數據流采用循環讀取的方式)來解決此問題,我還是把字符串的壓縮和解壓做一下簡單的記錄。
2.關於壓縮與解壓
壓縮算法有多種,我說知道和接觸有java I/O自帶的zip和gzip兩種方式。
本節主要來簡單介紹一下在系統交互之間遇到大容量的字符串數據交互時,采用一端壓縮,另一端再解壓的方式來發送和接收數據。
關於此次的壓縮和解壓用到的主要就是GZIPOutputStream和GZIPInputStream類,此類的相關介紹在JDK中有詳細的介紹,這里就不再累述了。
3.代碼如下:
壓縮:

1 /** 2 * 字符串的壓縮 3 * 4 * @param str 5 * 待壓縮的字符串 6 * @return 返回壓縮后的字符串 7 * @throws IOException 8 */ 9 public static String compress(String str) throws IOException { 10 if (null == str || str.length() <= 0) { 11 return str; 12 } 13 // 創建一個新的 byte 數組輸出流 14 ByteArrayOutputStream out = new ByteArrayOutputStream(); 15 // 使用默認緩沖區大小創建新的輸出流 16 GZIPOutputStream gzip = new GZIPOutputStream(out); 17 // 將 b.length 個字節寫入此輸出流 18 gzip.write(str.getBytes()); 19 gzip.close(); 20 // 使用指定的 charsetName,通過解碼字節將緩沖區內容轉換為字符串 21 return out.toString("ISO-8859-1"); 22 }
解壓:

1 /** 2 * 字符串的解壓 3 * 4 * @param str 5 * 對字符串解壓 6 * @return 返回解壓縮后的字符串 7 * @throws IOException 8 */ 9 public static String unCompress(String str) throws IOException { 10 if (null == str || str.length() <= 0) { 11 return str; 12 } 13 // 創建一個新的 byte 數組輸出流 14 ByteArrayOutputStream out = new ByteArrayOutputStream(); 15 // 創建一個 ByteArrayInputStream,使用 buf 作為其緩沖區數組 16 ByteArrayInputStream in = new ByteArrayInputStream(str 17 .getBytes("ISO-8859-1")); 18 // 使用默認緩沖區大小創建新的輸入流 19 GZIPInputStream gzip = new GZIPInputStream(in); 20 byte[] buffer = new byte[256]; 21 int n = 0; 22 while ((n = gzip.read(buffer)) >= 0) {// 將未壓縮數據讀入字節數組 23 // 將指定 byte 數組中從偏移量 off 開始的 len 個字節寫入此 byte數組輸出流 24 out.write(buffer, 0, n); 25 } 26 // 使用指定的 charsetName,通過解碼字節將緩沖區內容轉換為字符串 27 return out.toString("GBK"); 28 }
完整代碼的如下:

1 package gzip; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.ByteArrayOutputStream; 5 import java.io.IOException; 6 import java.util.zip.GZIPInputStream; 7 import java.util.zip.GZIPOutputStream; 8 9 /** 10 * 11 *Module: ZipUtil.java 12 *Description: 對字符串的壓縮及解壓 13 *Company: 14 *Author: pantp 15 *Date: May 6, 2012 16 */ 17 public class ZipStrUtil { 18 19 public static void main(String[] args) throws IOException { 20 // 字符串超過一定的長度 21 String str = "ABCdef123中文~!@#$%^&*()_+{};/1111111111111111111111111AAAAAAAAAAAJDLFJDLFJDLFJLDFFFFJEIIIIIIIIIIFJJJJJJJJJJJJALLLLLLLLLLLLLLLLLLLLLL" + 22 "LLppppppppppppppppppppppppppppppppppppppppp===========================------------------------------iiiiiiiiiiiiiiiiiiiiiii"; 23 System.out.println("\n原始的字符串為------->" + str); 24 float len0=str.length(); 25 System.out.println("原始的字符串長度為------->"+len0); 26 27 String ys = compress(str); 28 System.out.println("\n壓縮后的字符串為----->" + ys); 29 float len1=ys.length(); 30 System.out.println("壓縮后的字符串長度為----->" + len1); 31 32 String jy = unCompress(ys); 33 System.out.println("\n解壓縮后的字符串為--->" + jy); 34 System.out.println("解壓縮后的字符串長度為--->"+jy.length()); 35 36 System.out.println("\n壓縮比例為"+len1/len0); 37 38 //判斷 39 if(str.equals(jy)){ 40 System.out.println("先壓縮再解壓以后字符串和原來的是一模一樣的"); 41 } 42 } 43 44 /** 45 * 字符串的壓縮 46 * 47 * @param str 48 * 待壓縮的字符串 49 * @return 返回壓縮后的字符串 50 * @throws IOException 51 */ 52 public static String compress(String str) throws IOException { 53 if (null == str || str.length() <= 0) { 54 return str; 55 } 56 // 創建一個新的 byte 數組輸出流 57 ByteArrayOutputStream out = new ByteArrayOutputStream(); 58 // 使用默認緩沖區大小創建新的輸出流 59 GZIPOutputStream gzip = new GZIPOutputStream(out); 60 // 將 b.length 個字節寫入此輸出流 61 gzip.write(str.getBytes()); 62 gzip.close(); 63 // 使用指定的 charsetName,通過解碼字節將緩沖區內容轉換為字符串 64 return out.toString("ISO-8859-1"); 65 } 66 67 /** 68 * 字符串的解壓 69 * 70 * @param str 71 * 對字符串解壓 72 * @return 返回解壓縮后的字符串 73 * @throws IOException 74 */ 75 public static String unCompress(String str) throws IOException { 76 if (null == str || str.length() <= 0) { 77 return str; 78 } 79 // 創建一個新的 byte 數組輸出流 80 ByteArrayOutputStream out = new ByteArrayOutputStream(); 81 // 創建一個 ByteArrayInputStream,使用 buf 作為其緩沖區數組 82 ByteArrayInputStream in = new ByteArrayInputStream(str 83 .getBytes("ISO-8859-1")); 84 // 使用默認緩沖區大小創建新的輸入流 85 GZIPInputStream gzip = new GZIPInputStream(in); 86 byte[] buffer = new byte[256]; 87 int n = 0; 88 while ((n = gzip.read(buffer)) >= 0) {// 將未壓縮數據讀入字節數組 89 // 將指定 byte 數組中從偏移量 off 開始的 len 個字節寫入此 byte數組輸出流 90 out.write(buffer, 0, n); 91 } 92 // 使用指定的 charsetName,通過解碼字節將緩沖區內容轉換為字符串 93 return out.toString("GBK"); 94 } 95 96 }
4.測試效果
運行代碼中的main方式,測試的效果如下:
說明:
字符串長度很小的時候,測試時你會發現壓縮后的長度竟然變長了,字符串必須達到一定長度,壓縮比例就可以明顯看到很大。
哪位大蝦還有什么好的方式處理系統之間大容量數據交互的方式,請指點一二。
我現在的項目中用的是HTTP+JSON的方式。