zlib庫中,可以用compress2()函數對一塊記憶體區域進行壓縮,也可以使用gzopen()和gzwrite()兩個函數将記憶體中的資訊壓縮後寫入gz檔案。
測試中發現,如果把compress2()函數壓縮後的内容直接寫成檔案,這個檔案無法被gzip等程式打開,可見記憶體壓縮後的内容并不是一個标準的gz檔案。
compress2()函數與gzopen()函數所産生的壓縮内容到底有什麼不同呢?下面是我的實驗:
1、準備一個文本檔案,位元組數為9585位元組。
2、分别使用
gzopen("test_gzopen.txt.gz", "wb9")生成檔案test_gzopen.txt.gz,檔案長度4152
和compress2(dst, &dst_len, src, src_len, 9)生成檔案test_compress2.txt.gz,檔案長度4140
3、使用二進制編輯器檢視兩個gz檔案的内容,大部分是相同的。不同的部分為:
test_gzopen.txt.gz的前面10個位元組為:
1F 8B 08 00 00 00 00 00 00 0B
test_compress2.txt.gz的前面兩個位元組為:
78 DA
兩個檔案之後的4134個位元組相同
test_gzopen.txt.gz的最後8個位元組為:
83 1A E0 A6 71 25 00 00
test_compress2.txt.gz的最後4個位元組為:
44 75 8B EF
4、gzip檔案頭中,1F 8B為GZIP檔案的MAGIC NUMBER
gzip檔案的最後四個位元組是檔案的長度,Hex(71 25 00 00)=Dec(9585)
gzip檔案的倒數第五到第八個位元組是CRC32校驗碼
5、參考了一篇關于zlib的文章:http://blog.developers.api.sina.com.cn/?tag=zlib
猜想gzip檔案的檔案頭大約是這個含義
struct GzipHeader
{
char Id1; //1f
char Id2; //8b
char cm; //08 Z_DEFLATED
char flag; //00
char mime[4]; //00 00 00 00
char xfl; //00
char os; //0B 11-windows
};
結論:
可見,compress2()函數與gzopen()函數所産生的資料的壓縮内容是相同的,僅僅隻是産生的頭不同而已。
本來想寫一個函數,将compress2()的壓縮結果在記憶體中形成gzip的格式,但是校驗碼的問題一直搞不定,暫時未找到校驗碼是如何計算得出的,希望有這方面知識的朋友給我予指點,謝謝。
後記:
研究zlib的目的,是想要自己實作一個簡易的HTTP伺服器,需要在HTTP伺服器中實作内容的壓縮下載下傳。
在傳回的HTTP頭中加上Content-Encoding: deflate或Content-Encoding: gzip就可以對相應的内容部分進行壓縮輸出。
由于暫時沒辦法将compress2()函數壓縮的結果轉換為gzip格式,又不能使用gzopen()函數将資料壓縮成檔案再輸出(IO操作一定很慢)。研究了一下發現,其實很容易解決:将HTTP頭指定為deflate,将compress2()函數的壓縮結果輸出為:send(sock, buffer+2, compress_len-6)就實作了deflate方式的壓縮。
==========================
參考:
http://www.zlib.net/ zlib Home Site
http://blog.developers.api.sina.com.cn/?tag=zlib 18個位元組: gzip 與 deflate
========================================================
2009-04-02:補充
今天測試發現,使用deflate壓縮方式,不能隻輸出壓縮的資料部分,正确的輸出方式應該是:
send(sock, buffer+2, compress_len-2)
也就是說僅僅去掉compress2()壓縮後的前面兩個位元組,最後的四個位元組不能去掉,否則發送到用戶端的内容雖然能夠正确顯示,但是最後幾個位元組顯示不出來。
是以deflate壓縮方式應該隻比gzip壓縮方式少14位元組,而不是18個位元組。