摘要:同樣都是二進位序列化後壓縮為什麼壓縮後資料大小不一樣呢?
之前在寫 二進位序列化+壓縮 發現了一個問題。
下面的Compress_0、Compress_1 function同樣都是序列化後壓縮,
但是為什麼Compress_0壓縮不如Compress_1,怎麼不是一樣大呢???
讓我們來探討一下吧!
要序列化的資料結構
[Serializable] 
class date 
{ 
    public DateTime a1; 
    public DateTime a2; 
    public DateTime a3; 
    public DateTime a4; 
    public DateTime a5; 
    public DateTime a6; 
    public date() 
    { 
        a1 = a2 = a3 = a4 = a5 = a6 = DateTime.Now; 
    } 
} 
第一種壓縮方式(Compress_0 function),邊序列化邊壓縮
static byte[] Compress_0(date obj)
{
    MemoryStream zippedStream = new MemoryStream();
    using (GZipStream gzip = new GZipStream(zippedStream, CompressionMode.Compress))
    {
        BinaryFormatter bfmt = new BinaryFormatter();
        bfmt.Serialize(gzip, obj);
        gzip.Flush();
    }
    byte[] zippedBuf = zippedStream.ToArray();
    return zippedBuf;
}
第二種壓縮方式(Compress_1 function),將物件完全序列化後才一次全部壓縮
static byte[] Compress_1(date obj)
{
    //先將物件完全序列化
    BinaryFormatter ser = new BinaryFormatter();
    MemoryStream stream = new MemoryStream();
    stream.Position = 0;
    ser.Serialize(stream, obj);
    //將序列化完後的全部資料,進行壓縮      
    byte[] serbyte = stream.ToArray();
    MemoryStream ms = new MemoryStream();
    ms.Position = 0;
    using (GZipStream zipStream = new GZipStream(ms, CompressionMode.Compress))
    {
        zipStream.Write(serbyte, 0, serbyte.Length);
    }
    return ms.ToArray();
}
接下來讓我們透過WIN FROM執行上面兩個方法
private void button1_Click(object sender, EventArgs e)  
{  
	date myDate = new date(); //要序列化的物件
	var c0 = Compress_0(myDate);  
	var c1 = Compress_1(myDate); 
	label1.Text = c0.Length.ToString(); 
	label2.Text = c1.Length.ToString(); 
} 
執行結果如下(label1.Text=302、label2.Text =268,環境執行WIN7系統.net 4.0),WIN FORM去執行在XP x86和WIN7 X64及皆用.net 4.0跑但是label1.Text一直都沒有等於label2.Text
答案:經過google一番搜尋,發現有相關的解答。
static byte[] Compress_0(date obj)
{ 
	byte[] zippedBuf; 
	MemoryStream zippedStream = new MemoryStream();   
	using (GZipStream gzip = new GZipStream(zippedStream, CompressionMode.Compress))   
	{ 
	    using (var bstream = new BufferedStream(gzip, 65536))//設定Buffere大小64k 
	    { 
	        BinaryFormatter bfmt = new BinaryFormatter(); //將序列化加一個64k BufferedStream做為緩衝區
	        bfmt.Serialize(bstream, obj); 
	                             
	    } 
	    zippedBuf = zippedStream.ToArray();  
	}   
	           	                      
	return zippedBuf;   
}
額外補充:
在取出MemoryStream.ToArray()前必須先關閉相關的Stream(如GZipStream或BufferedStream),否則在反序列化時,會有SerializationException的錯誤。 
感恩下面的作者
相關參考:http://stackoverflow.com/questions/12091404/using-gzipstream-with-one-or-two-memory-streams-makes-a-big-difference
相關參考:http://stackoverflow.com/questions/12088623/how-to-serialize-object-compress-it-and-then-decompress-deserialize-without
相關參考:http://stackoverflow.com/questions/12088623/how-to-serialize-object-compress-it-and-then-decompress-deserialize-without

