在抓取頁面的過程中,在存儲抓取到的頁面內容的時候我需要先將頁面壓縮再存儲, 為了使用上的方便,采用了2.0下的GZipStream來進行壓縮。
引用如下:
using System.IO;
using System.IO.Compression;
......
public static byte[] Compress(byte[] data)
{
MemoryStream stream = new MemoryStream();
GZipStream gZipStream = new GZipStream(stream, CompressionMode.Compress);
gZipStream.Write(data, 0, data.Length);
//....暫時先在注釋的位置賣點關子
return stream.ToArray();
}
public static byte[] Decompress(byte[] data)
{
MemoryStream stream = new MemoryStream();
GZipStream gZipStream = new GZipStream(new MemoryStream(data), CompressionMode.Decompress);
byte[] bytes = new byte[4096];
int n;
while ((n = gZipStream.Read(bytes, 0, bytes.Length)) != 0)
{
stream.Write(bytes, 0, n);
}
return stream.ToArray();
}
上面的代碼使用起來似乎是沒有什麼問題的(如果你不仔細做測試的話), 但是當我對各種大小的頁面進行測試後,發現如果壓縮後byte[]長度<4K,那麼問題出 來了:沒法解壓,解壓函數中Read返回結果總是0。聞一多先生曾經在演講中說“郁 悶啊,郁悶,這是某集團的郁悶,恰恰是微軟的光榮(筆者注:我覺得應該屬於微軟bug )”。
我一度懷疑是不是Decompress函數中的bytes數組長度設置長了,後來把長度設置的很 小,但是解壓後還是那樣,返回0。真想去和蓋茨理論理論。
不過幸運的是,我測試發現了這個4K下限制,所以Google了下“GZipStream 4K”,哈哈,在國外的一論壇 (http://www.dotnetmonster.com/Uwe/Forum.ASPx/dotnet-framework/19787/Problem- with-the-GZipStream-class-and-small-streams)裡面終於找到了答案:原來 GZipStream存取數據的時候是以4K為塊進行存取的。所以在壓縮的時候,在返回 stream.ToArray()前應該先gZipStream.Close()(也就是上面俺賣關子的那裡),原因是 GZipStream是在Dispose的時候把數據完全寫入。你說冤嗎?我明明已經Write了,竟然還 要我再Close才可以。