Zlib庫的安裝與使用

  在實際應用中常常會遇到要壓縮數據的問題,常見的壓縮格式有zip和rar,而Linux下那就更多了,bz2,gz,xz什麼的都有,單單Linux下的解壓和壓縮命令就有好多呢?沒有什麼好很差的。查了資料,應該是zlib這個比較簡單好用。應用也廣,因此就準備用這個了。html

  下載Zlib庫,地址: http://zlib.net/zlib128.zip 用wget下載,而後再用unzip解壓一下,而後就像通常軟件同樣 ./configure && make && make install .(注意要root權限)瀏覽器

  下面這個是安裝信息服務器

 1 cp libz.a /usr/local/lib
 2 chmod 644 /usr/local/lib/libz.a
 3 cp libz.so.1.2.8 /usr/local/lib
 4 chmod 755 /usr/local/lib/libz.so.1.2.8
 5 cp zlib.3 /usr/local/share/man/man3
 6 chmod 644 /usr/local/share/man/man3/zlib.3
 7 cp zlib.pc /usr/local/lib/pkgconfig
 8 chmod 644 /usr/local/lib/pkgconfig/zlib.pc
 9 cp zlib.h zconf.h /usr/local/include
10 chmod 644 /usr/local/include/zlib.h /usr/local/include/zconf.h

  寫一個簡單的例子測試一下,注意編譯的時候要加入 -lz 這個庫app

 1 #include <stdio.h>
 2 #include <zlib.h>
 3 
 4 int main(int argc,char **args)
 5 {
 6     /*原始數據*/
 7     unsigned char strsrc[]="這些是測試數據。123456789 abcdefghigklmnopqrstuvwxyz\n\t\0abcdefghijklmnopqrstuvwxyz\n"; //包含\0字符
 8     unsigned char buf[1024]={0};
 9     unsigned char strdst[1024]={0};
10     unsigned long srclen=sizeof(strsrc);
11     unsigned long buflen=sizeof(buf);
12     unsigned long dstlen=sizeof(strdst);
13     int i;
14     FILE * fp;
15 
16     printf("源串:");
17     for(i=0;i<srclen;++i)
18     {
19         printf("%c",strsrc[i]);
20     }
21     printf("原串長度爲:%ld\n",srclen);
22 
23     printf("字符串預計算長度爲:%ld\n",compressBound(srclen));
24     //壓縮
25     compress(buf,&buflen,strsrc,srclen);
26     printf("壓縮後實際長度爲:%ld\n",buflen);
27     //解壓縮
28     uncompress(strdst,&dstlen,buf,buflen);
29 
30     printf("目的串:");
31     for(i=0;i<dstlen;++i)
32     {
33         printf("%c",strdst[i]);
34     }
35 
36     return 0;
37 }

  各個APIdom

 1 //把源緩衝壓縮成到目的緩衝,一個函數就完成了
 2 int compress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
 3 
 4 //功能和compress函數同樣,多了一個參數能夠指定壓縮質量和壓縮數度之間的關係(0-9)。要想獲得高的壓縮比就要多花時間
 5 int compress2 (Bytef *dest, uLongf *destLen,const Bytef *source, uLong sourceLen,int level);
 6 
 7 //計算須要的緩衝區長度. 假設你在壓縮以前就想知道你的產度爲 sourcelen 的數據壓縮後有多大, 可調用這個函數計算一下,這個函數並不能獲得精確的結果,可是它能夠保證明際輸出長度確定小於它計算出來的長度
 8 uLong compressBound (uLong sourceLen);
 9 
10 //解壓縮
11 int uncompress (Bytef *dest, uLongf *destLen,const Bytef *source, uLong sourceLen);

  處理gz後綴的壓縮文件。socket

  壓縮字符串到test.gzide

 1 #include <stdio.h>
 2 #include <zlib.h>
 3 
 4 int main(int argc,char **args)
 5 {
 6     gzFile file;
 7     char str[]="testtest";
 8     file=gzopen("test.gz","wb");
 9     if(NULL==file)
10         perror("Can't open file");
11     gzsetparams(file,2,0);
12     gzwrite(file,str,sizeof(str));
13     gzclose(file);
14     return 0;
15 }

  解壓test.gz函數

 1 #include <stdio.h>
 2 #include <zlib.h>
 3 
 4 int main(int argc,char **args)
 5 {
 6     gzFile file;
 7     char str[64]={0};
 8     file=gzopen("test.gz","rb");
 9     if(NULL==file)
10         perror("Can't open file");
11     gzread(file,str,10);
12     printf("從文件中讀取到的字符:%s.\n",str);
13     gzclose(file);
14     return 0;
15 }

  對於test.gz這個文件若是不知道是否正確,可使用系統命令zcat進行查看。還有一個問題就是個壓縮包只能解壓出一個文件,是不可能存在多個文件的。 這是GZIP的特性決定了的。 一般,都是把多個文件用tar先壓成一個包,而後在gzip。這就是爲何下載的軟件源碼包大多都是 .tar.gz 這樣的格式。測試

  對於gz文件處理的APIspa

 1 //注意下面介紹到的處理函數,跟通常文件的處理函數是類似的,效果也是差很少的。
 2 typedef voidp gzFile;
 3 
 4 //打開一個gzip文件進行讀/寫,mode和fopen("rb"或" wb")同樣.也能夠包括壓縮級別如:"wb9",或着一個策略"f"做爲過濾數據"wb6f", "h"是爲了"huffman" 壓縮,如:"wb1h".gzopen用於讀一個沒有gzip格式的文件.gzread直接從沒有解壓縮的文件中讀數據.若是文件不能被打開或是沒有足夠的內存,gzopen將返回NULL.
 5 gzFile gzopen(const char *path,const char *mode);
 6 
 7 //根據文件描述符打開一個gz文件
 8 gzFile gzdopen (int fd, const char *mode);
 9 
10 //動態更新壓縮等級和壓縮格式 成功返回Z_OK 不然返回Z_STREAM_ERROR
11 int gzsetparams (gzFile file, int level, int strategy);
12 
13 //讀取所給的個數len字節。從壓縮文件中讀取解壓後的字符的個數。 若是file不是gzip格式,那麼就讀取實際的字節個數,而不是解壓後的實際個數。成功返回所讀取的個數,0表示文件結束,-1表示錯誤。
14 //英文原文 Reads the given number of uncompressed bytes from the compressed file.If the input file was not in gzip format, gzread copies the given number of bytes into the buffer.
15 int gzread (gzFile file,voidp buf, unsigned int len);
16 
17 //寫入所給長度的buf字符到file中 成功返回所寫入的字符個數,0表示寫入失敗
18 int gzwrite(gzFile file, voidp buf,unsigned int len);
19 
20 //能夠看到下面介紹到的全部函數都跟咱們處理普通的文件同樣,把函數的gz換成f,是否是就熟悉了許多?大概就是這樣吧
21 int gzprintf(gzFile file,const char *format, ...);
22 int gzputs(gzFile file,const char *s);
23 char * gzgets(gzFile file, char *buf,int len);
24 int gzputc(gzFile file,int c);
25 int gzgetc(gzFile file);
26 int gzungetc(int c,gzFile file);
27 int gzflush (gzFile file,int flush);
28 int gzseek (gzFile file,z_off_t offset, int whence);
29 int gzrewind(gzFile file);
30 z_off_t gztell(gzFile file);
31 int gzeof(gzFile file);
32 int gzdirect(gzFile file);
33 int gzclose(gzFile file);
34 const char * gzerror(gzFile file, int *errnum);
35 void gzclearerr(gzFile file);

  計算校驗碼

 1 uLong adler32 (uLong adler,const Bytef *buf, uInt len);
 2 //使用方法以下
 3 uLong adler=adler32(0L,Z_NULL,0);
 4 while(read_buffer(buffer, length) !=EOF)
 5 {
 6     adler=adler32(adler,buffer,length);
 7 }
 8 if(adler != original_adler)
 9     error();
10 
11 uLong crc32 (uLong crc,const Bytef *buf,uInt len);
12 //使用方法以下
13 uLong crc = crc32(0L,Z_NULL,0);
14 while(read_buffer(buffer,length)!=EOF)
15 {
16     crc=crc32(crc,buffer,length);
17 }
18 if(crc != original_crc)
19     error();

  最後是z_stream這個結構了

 1 typedef struct z_stream_s {
 2     Bytef    *next_in;  /* next input byte */
 3     uInt     avail_in;  /* number of bytes available at next_in */
 4     uLong    total_in;  /* total nb of input bytes read so far */
 5 
 6     Bytef    *next_out; /* next output byte should be put there */
 7     uInt     avail_out; /* remaining free space at next_out */
 8     uLong    total_out; /* total nb of bytes output so far */
 9 
10     char     *msg;      /* last error message, NULL if no error */
11     struct internal_state FAR *state; /* not visible by applications */
12 
13     alloc_func zalloc;  /* used to allocate the internal state */
14     free_func  zfree;   /* used to free the internal state */
15     voidpf     opaque;  /* private data object passed to zalloc and zfree */
16 
17     int     data_type;  /* best guess about the data type: binary or text */
18     uLong   adler;      /* adler32 value of the uncompressed data */
19     uLong   reserved;   /* reserved for future use */
20 } z_stream;
1 deflateInit() + deflate() + deflateEnd()
2 //3個函數結合使用完成壓縮功能,具體用法看 example.c 的 test_deflate()函數. 其實compress() 函數內部就是用這3個函數實現的
3 
4 inflateInit() + inflate() + inflateEnd()
5 //上面相似,完成解壓縮功能.

  下面給出一個example方面查看,瞭解函數的用法,不過通常應用程序用到上面的函數便可。

  1 /* zpipe.c: example of proper use of zlib's inflate() and deflate()
  2    Not copyrighted -- provided to the public domain
  3    Version 1.4  11 December 2005  Mark Adler */
  4 
  5 /* Version history:
  6    1.0  30 Oct 2004  First version
  7    1.1   8 Nov 2004  Add void casting for unused return values
  8                      Use switch statement for inflate() return values
  9    1.2   9 Nov 2004  Add assertions to document zlib guarantees
 10    1.3   6 Apr 2005  Remove incorrect assertion in inf()
 11    1.4  11 Dec 2005  Add hack to avoid MSDOS end-of-line conversions
 12                      Avoid some compiler warnings for input and output buffers
 13  */
 14 
 15 #include <stdio.h>
 16 #include <string.h>
 17 #include <assert.h>
 18 #include "zlib.h"
 19 
 20 #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
 21 #  include <fcntl.h>
 22 #  include <io.h>
 23 #  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
 24 #else
 25 #  define SET_BINARY_MODE(file)
 26 #endif
 27 
 28 #define CHUNK 16384
 29 
 30 /* Compress from file source to file dest until EOF on source.
 31    def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
 32    allocated for processing, Z_STREAM_ERROR if an invalid compression
 33    level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
 34    version of the library linked do not match, or Z_ERRNO if there is
 35    an error reading or writing the files. */
 36 int def(FILE *source, FILE *dest, int level)
 37 {
 38     int ret, flush;
 39     unsigned have;
 40     z_stream strm;
 41     unsigned char in[CHUNK];
 42     unsigned char out[CHUNK];
 43 
 44     /* allocate deflate state */
 45     strm.zalloc = Z_NULL;
 46     strm.zfree = Z_NULL;
 47     strm.opaque = Z_NULL;
 48     ret = deflateInit(&strm, level);
 49     if (ret != Z_OK)
 50         return ret;
 51 
 52     /* compress until end of file */
 53     do {
 54         strm.avail_in = fread(in, 1, CHUNK, source);
 55         if (ferror(source)) {
 56             (void)deflateEnd(&strm);
 57             return Z_ERRNO;
 58         }
 59         flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
 60         strm.next_in = in;
 61 
 62         /* run deflate() on input until output buffer not full, finish
 63            compression if all of source has been read in */
 64         do {
 65             strm.avail_out = CHUNK;
 66             strm.next_out = out;
 67             ret = deflate(&strm, flush);    /* no bad return value */
 68             assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
 69             have = CHUNK - strm.avail_out;
 70             if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
 71                 (void)deflateEnd(&strm);
 72                 return Z_ERRNO;
 73             }
 74         } while (strm.avail_out == 0);
 75         assert(strm.avail_in == 0);     /* all input will be used */
 76 
 77         /* done when last data in file processed */
 78     } while (flush != Z_FINISH);
 79     assert(ret == Z_STREAM_END);        /* stream will be complete */
 80 
 81     /* clean up and return */
 82     (void)deflateEnd(&strm);
 83     return Z_OK;
 84 }
 85 
 86 /* Decompress from file source to file dest until stream ends or EOF.
 87    inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
 88    allocated for processing, Z_DATA_ERROR if the deflate data is
 89    invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
 90    the version of the library linked do not match, or Z_ERRNO if there
 91    is an error reading or writing the files. */
 92 int inf(FILE *source, FILE *dest)
 93 {
 94     int ret;
 95     unsigned have;
 96     z_stream strm;
 97     unsigned char in[CHUNK];
 98     unsigned char out[CHUNK];
 99 
100     /* allocate inflate state */
101     strm.zalloc = Z_NULL;
102     strm.zfree = Z_NULL;
103     strm.opaque = Z_NULL;
104     strm.avail_in = 0;
105     strm.next_in = Z_NULL;
106     ret = inflateInit(&strm);
107     if (ret != Z_OK)
108         return ret;
109 
110     /* decompress until deflate stream ends or end of file */
111     do {
112         strm.avail_in = fread(in, 1, CHUNK, source);
113         if (ferror(source)) {
114             (void)inflateEnd(&strm);
115             return Z_ERRNO;
116         }
117         if (strm.avail_in == 0)
118             break;
119         strm.next_in = in;
120 
121         /* run inflate() on input until output buffer not full */
122         do {
123             strm.avail_out = CHUNK;//CHUNK=128K 124             strm.next_out = out;
125             ret = inflate(&strm, Z_NO_FLUSH);
126             assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
127             switch (ret) {
128             case Z_NEED_DICT:
129                 ret = Z_DATA_ERROR;     /* and fall through */
130             case Z_DATA_ERROR:
131             case Z_MEM_ERROR:
132                 (void)inflateEnd(&strm);
133                 return ret;
134             }
135             have = CHUNK - strm.avail_out;
136             if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
137                 (void)inflateEnd(&strm);
138                 return Z_ERRNO;
139             }
140         } while (strm.avail_out == 0);
141 
142         /* done when inflate() says it's done */
143     } while (ret != Z_STREAM_END);
144 
145     /* clean up and return */
146     (void)inflateEnd(&strm);
147     return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
148 }
149 
150 /* report a zlib or i/o error */
151 void zerr(int ret)
152 {
153     fputs("zpipe: ", stderr);
154     switch (ret) {
155     case Z_ERRNO:
156         if (ferror(stdin))
157             fputs("error reading stdin\n", stderr);
158         if (ferror(stdout))
159             fputs("error writing stdout\n", stderr);
160         break;
161     case Z_STREAM_ERROR:
162         fputs("invalid compression level\n", stderr);
163         break;
164     case Z_DATA_ERROR:
165         fputs("invalid or incomplete deflate data\n", stderr);
166         break;
167     case Z_MEM_ERROR:
168         fputs("out of memory\n", stderr);
169         break;
170     case Z_VERSION_ERROR:
171         fputs("zlib version mismatch!\n", stderr);
172     }
173 }
174 
175 /* compress or decompress from stdin to stdout */
176 int main(int argc, char **argv)
177 {
178     int ret;
179 
180     /* avoid end-of-line conversions */
181     SET_BINARY_MODE(stdin);
182     SET_BINARY_MODE(stdout);
183 
184     /* do compression if no arguments */
185     if (argc == 1) {
186         ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION);
187         if (ret != Z_OK)
188             zerr(ret);
189         return ret;
190     }
191 
192     /* do decompression if -d specified */
193     else if (argc == 2 && strcmp(argv[1], "-d") == 0) {
194         ret = inf(stdin, stdout);
195         if (ret != Z_OK)
196             zerr(ret);
197         return ret;
198     }
199 
200     /* otherwise, report usage */
201     else {
202         fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr);
203         return 1;
204     }
205 }

  接下來給出一個實例來了解一下gzip。 

  Web服務器實現gzip壓縮發送

  1 #include <string.h>
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <errno.h>
  5 #include <sys/types.h>
  6 #include <sys/socket.h>
  7 #include <netinet/in.h>
  8 #include <arpa/inet.h>
  9 #include <unistd.h>
 10 #include <signal.h>
 11 #include <zlib.h>
 12 #include <zconf.h>
 13 
 14 void app_exit();
 15 int socket_listen(u_short port);
 16 void send_http_head(int clifd);
 17 void put_long (unsigned char *string, unsigned long x);
 18 int gzip_http_buffer(int clifd,char *msg,int len);
 19 
 20 
 21 int sockfd;
 22 int main(int argc,char **args)
 23 {
 24     struct sockaddr_in cli_sin;
 25     socklen_t cli_len=sizeof(cli_sin);
 26     int clifd;
 27     char buf[4096];
 28     char msg[4096]="<br><br><h1>Reage Web Server gzip support text!</h1><br/><h1><a href = \"http://wunaozai.cnblogs.com\">Reage blog</a>";
 29 
 30     signal(SIGINT,app_exit);
 31     sockfd=socket_listen(8080);
 32     while(1)
 33     {
 34         clifd=accept(sockfd,(struct sockaddr *)&cli_sin,&cli_len);
 35         printf("鏈接進來的IP:%s:%u\n",inet_ntoa(cli_sin.sin_addr),ntohs(cli_sin.sin_port));
 36         read(clifd,buf,4096);
 37         printf("%s\n",buf);
 38         send_http_head(clifd);
 39         gzip_http_buffer(clifd,msg,strlen(msg));
 40 
 41         close(clifd);
 42     }
 43     close(sockfd);
 44     return 0;
 45 }
 46 
 47 void put_long (unsigned char *string, unsigned long x)//對於gzip後面的兩個字節進行位填充,這裏應該是處理大端與小端
 48 {
 49     string[0] = (x & 0xff);
 50     string[1] = ((x >> 8) & 0xff) ;
 51     string[2] = ((x >> 16) & 0xff) ;
 52     string[3] = ((x >> 24) & 0xff);
 53 }
 54 /*
 55  * 對要發送的msg裏面的字符進行壓縮發送
 56  * gzip格式: http://www.cnblogs.com/witxjp/archive/2003/12/17/1986210.html
 57  * */
 58 static const char gzip_header[10]={0x1f,0x8b,0x08,0,0,0,0,0,0,0x03};
 59 int gzip_http_buffer(int clifd,char *msg,int len)
 60 {
 61     z_stream stream;
 62     int ret,flush;
 63     char in[4096];//存放輸入的數據
 64     char send[4096+18];//存放壓縮事後的數據
 65     unsigned int have;
 66     int tmp;
 67     memcpy(send,gzip_header,10);
 68     memset(in,0,len);
 69     stream.zalloc=Z_NULL;
 70     stream.zfree=Z_NULL;
 71     stream.opaque=Z_NULL;
 72     stream.avail_in=0;
 73     stream.next_in=Z_NULL;
 74     memcpy(in,msg,len);
 75     //壓縮初始化
 76     tmp=deflateInit2(&stream,
 77             Z_DEFAULT_COMPRESSION,//壓縮級別,從0-9
 78             Z_DEFLATED,//壓縮方式
 79             -MAX_WBITS,
 80             8,
 81             Z_DEFAULT_STRATEGY);
 82     if(Z_OK!=tmp)
 83     {
 84         perror("deflateInit2 Error");
 85         return 0;
 86     }
 87     stream.avail_in = len; //要壓縮數據的長度
 88     stream.next_in = in;    //要壓縮數據的首地址
 89     stream.avail_out = 4096;  //可存放的最大輸出結果的長多。就是壓縮後數據的最大長度
 90     stream.next_out = send + 10; //存放壓縮數據的開始位置,send前十個字節用來放頭部
 91     ret = deflate (&stream,Z_FINISH); //壓縮
 92     switch(ret)
 93     {
 94         case Z_NEED_DICT:
 95             ret=Z_DATA_ERROR;
 96         case Z_DATA_ERROR:
 97         case Z_MEM_ERROR:
 98             (void)inflateEnd(&stream);
 99             return ret;
100     }
101     have = 4096 - stream.avail_out;
102     unsigned crc = crc32(0L, in, len);
103     char * tail = send + 10 + have;
104     put_long (tail, crc);
105     put_long (tail + 4, len);
106     write (clifd, send, have + 18);
107     deflateEnd (&stream);
108     return 1;
109 }
110 
111 void app_exit()
112 {
113     signal(SIGINT,SIG_DFL);
114     close(sockfd);
115     exit(0);
116 }
117 
118 /*
119  * 發送一個HTTP頭
120  * */
121 void send_http_head(int clifd)
122 {
123     char buf[4096];
124     memset(buf,0,sizeof(buf));
125     sprintf(buf,"HTTP/1.1 200 OK\r\n");
126     sprintf(buf,"%sServer:wunaozai.cnblogs.com\r\n",buf);
127     sprintf(buf,"%sContent-Encoding: gzip\r\n",buf);//告訴瀏覽器,我接下來發送的數據是通過gzip壓縮過的
128     sprintf(buf,"%sContent-Type: text/html\r\n\r\n",buf);
129     write(clifd,buf,strlen(buf));
130 }
131 
132 /*
133  * 開啓服務器監聽
134  * port:服務器端口
135  * 成功返回套接字標識
136  * */
137 int socket_listen(u_short port)
138 {
139     struct sockaddr_in sin;
140     int on;
141     int httpd=socket(PF_INET,SOCK_STREAM,0);
142     if(httpd==-1)
143         perror("Fail to Socket");
144     //init sockaddr_in
145     sin.sin_family=AF_INET;
146     sin.sin_port=htons(port);
147     sin.sin_addr.s_addr=htonl(INADDR_ANY);
148     bzero(&(sin.sin_zero),8);
149     setsockopt(httpd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
150     if(bind(httpd,(struct sockaddr *)&sin,sizeof(struct sockaddr))==-1)
151         perror("Fail to bind");
152     //若是port指定爲零那麼就隨機打開一個端口
153     if(port==0)
154     {
155         socklen_t len=sizeof(sin);
156         if(getsockname(httpd,(struct sockaddr *)&sin,&len)==-1)
157             perror("Fail to getsockname");
158         port=ntohs(sin.sin_port);
159     }
160     if(listen(httpd,100)<0)
161         perror("Fail to listen");
162     printf("打開端口:%u\n",port);
163     return httpd;
164 }

 

 

  參考資料: http://blog.csdn.net/reage11/article/details/8517631

      : http://www.cppblog.com/Streamlet/archive/2010/09/22/127368.aspx

      : http://blog.csdn.net/htttw/article/details/7616124

      : http://www.cppblog.com/woaidongmao/archive/2009/09/07/95495.html

      : http://blog.csdn.net/zhoudaxia/article/details/8039519

  本文地址: http://www.cnblogs.com/wunaozai/p/3960494.html

相關文章
相關標籤/搜索