天天看點

ZLIB:gzopen與compress2函數壓縮的内容有什麼不同?

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個位元組。