Zlib

zlib是提供数据压缩用 的函式库,由Jean-loup Gailly与Mark Adler所开发,初版0.9版在1995年5月1日发表。zlib使用DEFLATE算法,最初是为libpng函式库所写的,后来普遍为许多软件所使 用。此函式库为自由软件,使用zlib授权。截至2007年3月,zlib是包含在Coverity的美国国土安全部赞助者选择继续审查的开源项目。

特性

编辑

数据头(header)

zlib能使用一个gzip数据头,zlib数据头或者不使用数据头压缩数据。
通常情况下,数据压缩使用zlib数据头,因为这提供错误数据检测。当数据不使用数据头写入时,结果是没有任何错误检测的原始DEFLATE数据,那么解压缩软件的调用者不知道压缩数据在什么地方结束。
gzip数据头比zlib数据头要大,因为它保存了文件名和其他文件系统信息,事实上这是广泛使用的gzip文件的数据头格式。注意zlib函式库本身不能创建一个gzip文件,但是它相当轻松的通过把压缩数据写入到一个有gzip文件头的文件中。

算法

目前zlib仅支持一个LZ77的变种算法,DEFLATE的算法。
这个算法使用很少的系统资源,对各种数据提供很好的压缩效果。这也是在ZIP档案中无一例外的使用这个算法。(尽管zip文件格式也支持几种其他的算法)。
看起来zlib格式将不会被扩展使用任何其他算法,尽管数据头可以有这种可能性。

使用资源

函数库提供了对处理器和内存使用控制的能力
不同的压缩级别数值可以指示不同的压缩执行速度。
还有内存控制管理的功能。这在一些诸如嵌入式系统这样内存有限制的环境中是有用的。

策略

压缩可以针对特定类型的数据进行优化
如果你总是使用zlib库压缩压缩特定类型的数据,那么可以使用有针对性的策略可以提高压缩效率和性能。例如,如果你的数据包含很长的重复数据,那么可以用RLE(运行长度编码)策略,可能会有更好的结果。
对于一般的数据,默认的策略是首选。

错误处理

错误可以被发现和跳过
数据混乱可以被检测(只要数据和zlib或者gzip数据头一起被写入-参见上面)
此外,如果全刷新点(full-flush points)被写入到压缩后的数据流中,那么错误数据是可以被跳过的,并且解压缩将重新同步到下个全刷新点。(错误数据的无错恢复被提供)。全刷新点技术对于在不可靠的通道上的大数据流是很有用的,一些过去的数据丢失是不重要的(例如多媒体数据),但是建立太多的全刷新点会极大的影响速度和压缩。

数据长度

对于压缩和解压缩,没有数据长度的限制
重复调用库函数允许处理无限的数据块。一些辅助代码(计数变量)可能会溢出,但是不影响实际的压缩和解压缩。
当压缩一个长(无限)数据流时,最好写入全刷新点。

业界应用

编辑
今天,zlib是一种事实上的业界标准,以至于在标准文档中,zlib和DEFLATE常常互换使用。数以千计的应用程序直接或间接依靠zlib压缩函式库,包括:
* Linux核心:使用zlib以实作网络协定的压缩、档案系统的压缩以及开机时解压缩自身的核心。
* libpng,用于PNG图形格式的一个实现,对bitmap数据规定了DEFLATE作为流压缩方法。
* Apache:使用zlib实作http 1.1。
* OpenSSH、OpenSSL:以zlib达到最佳化加密网络传输。
* FFmpeg:以zlib读写Matroska等以DEFLATE算法压缩的多媒体串流格式。
* rsync:以zlib最佳化远端同步时的传输。
* The dpkg and RPM package managers, which use zlib to unpack files from compressed software packages.
* Subversion 、Git和 CVS 版本控制 系统,使用zlib来压缩和远端仓库的通讯流量。
* dpkg和RPM等包管理软件:以zlib解压缩RPM或者其他封包
因为其代码的可移植性,宽松的许可以及较小的内存占用,zlib在许多嵌入式设备中也有应用。

使用范例

以下代码可直接用于解压HTTP gzip
  1 #include <stdlib.h>
  2 #include <string.h>
  3 #include <errno.h>
  4 #include <zlib.h>
  5 /* Compress data */
  6 int zcompress(Bytef *data, uLong ndata, Bytef *zdata, uLong *nzdata)
  7 {
  8   z_stream c_stream;
  9   int err = 0;
 10   if(data && ndata > 0)
 11   {
 12     c_stream.zalloc = (alloc_func)0;
 13     c_stream.zfree = (free_func)0;
 14     c_stream.opaque = (voidpf)0;
 15     if(deflateInit(&c_stream, Z_DEFAULT_COMPRESSION) != Z_OK)
 16       return -1;
 17     c_stream.next_in = data;
 18     c_stream.avail_in = ndata;
 19     c_stream.next_out = zdata;
 20     c_stream.avail_out = *nzdata;
 21     while (c_stream.avail_in != 0 && c_stream.total_out < *nzdata)
 22     {
 23       if(deflate(&c_stream, Z_NO_FLUSH) != Z_OK) return -1;
 24     }
 25     if(c_stream.avail_in != 0) return c_stream.avail_in;
 26     for (;;) {
 27       if((err = deflate(&c_stream, Z_FINISH)) == Z_STREAM_END) break;
 28       if(err != Z_OK) return -1;
 29     }
 30     if(deflateEnd(&c_stream) != Z_OK) return -1;
 31     *nzdata = c_stream.total_out;
 32     return 0;
 33    }
 34    return -1;
 35   }
 36 /* Compress gzip data */
 37 int gzcompress(Bytef *data, uLong ndata,
 38 Bytef *zdata, uLong *nzdata)
 39 {
 40 z_stream c_stream;
 41 int err = 0;
 42 if(data && ndata > 0)
 43 {
 44 c_stream.zalloc = (alloc_func)0;
 45 c_stream.zfree = (free_func)0;
 46 c_stream.opaque = (voidpf)0;
 47 if(deflateInit2(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
 48 -MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK) return -1;
 49 c_stream.next_in = data;
 50 c_stream.avail_in = ndata;
 51 c_stream.next_out = zdata;
 52 c_stream.avail_out = *nzdata;
 53 while (c_stream.avail_in != 0 && c_stream.total_out < *nzdata)
 54 {
 55 if(deflate(&c_stream, Z_NO_FLUSH) != Z_OK) return -1;
 56 }
 57 if(c_stream.avail_in != 0) return c_stream.avail_in;
 58 for (;;) {
 59 if((err = deflate(&c_stream, Z_FINISH)) == Z_STREAM_END) break;
 60 if(err != Z_OK) return -1;
 61 }
 62 if(deflateEnd(&c_stream) != Z_OK) return -1;
 63 *nzdata = c_stream.total_out;
 64 return 0;
 65 }
 66 return -1;
 67 }
 68 /* Uncompress data */
 69 int zdecompress(Byte *zdata, uLong nzdata,
 70 Byte *data, uLong *ndata)
 71 {
 72 int err = 0;
 73 z_stream d_stream; /* decompression stream */
 74 d_stream.zalloc = (alloc_func)0;
 75 d_stream.zfree = (free_func)0;
 76 d_stream.opaque = (voidpf)0;
 77 d_stream.next_in = zdata;
 78 d_stream.avail_in = 0;
 79 d_stream.next_out = data;
 80 if(inflateInit(&d_stream) != Z_OK) return -1;
 81 while (d_stream.total_out < *ndata && d_stream.total_in < nzdata) {
 82 d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
 83 if((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END) break;
 84 if(err != Z_OK) return -1;
 85 }
 86 if(inflateEnd(&d_stream) != Z_OK) return -1;
 87 *ndata = d_stream.total_out;
 88 return 0;
 89 }
 90 /* HTTP gzip decompress */
 91 int httpgzdecompress(Byte *zdata, uLong nzdata,
 92 Byte *data, uLong *ndata)
 93 {
 94 int err = 0;
 95 z_stream d_stream = {0}; /* decompression stream */
 96 static char dummy_head[2] =
 97 {
 98 0x8 + 0x7 * 0x10,
 99 (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
100 };
101 d_stream.zalloc = (alloc_func)0;
102 d_stream.zfree = (free_func)0;
103 d_stream.opaque = (voidpf)0;
104 d_stream.next_in = zdata;
105 d_stream.avail_in = 0;
106 d_stream.next_out = data;
107 if(inflateInit2(&d_stream, 47) != Z_OK) return -1;
108 while (d_stream.total_out < *ndata && d_stream.total_in < nzdata) {
109 d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
110 if((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END) break;
111 if(err != Z_OK )
112 {
113 if(err == Z_DATA_ERROR)
114 {
115 d_stream.next_in = (Bytef*) dummy_head;
116 d_stream.avail_in = sizeof(dummy_head);
117 if((err = inflate(&d_stream, Z_NO_FLUSH)) != Z_OK)
118 {
119 return -1;
120 }
121 }
122 else return -1;
123 }
124 }
125 if(inflateEnd(&d_stream) != Z_OK) return -1;
126 *ndata = d_stream.total_out;
127 return 0;
128 }
129 /* Uncompress gzip data */
130 int gzdecompress(Byte *zdata, uLong nzdata,
131 Byte *data, uLong *ndata)
132 {
133 int err = 0;
134 z_stream d_stream = {0}; /* decompression stream */
135 static char dummy_head[2] =
136 {
137 0x8 + 0x7 * 0x10,
138 (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
139 };
140 d_stream.zalloc = (alloc_func)0;
141 d_stream.zfree = (free_func)0;
142 d_stream.opaque = (voidpf)0;
143 d_stream.next_in = zdata;
144 d_stream.avail_in = 0;
145 d_stream.next_out = data;
146 if(inflateInit2(&d_stream, -MAX_WBITS) != Z_OK) return -1;
147 //if(inflateInit2(&d_stream, 47) != Z_OK) return -1;
148 while (d_stream.total_out < *ndata && d_stream.total_in < nzdata) {
149 d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
150 if((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END) break;
151 if(err != Z_OK )
152 {
153 if(err == Z_DATA_ERROR)
154 {
155 d_stream.next_in = (Bytef*) dummy_head;
156 d_stream.avail_in = sizeof(dummy_head);
157 if((err = inflate(&d_stream, Z_NO_FLUSH)) != Z_OK)
158 {
159 return -1;
160 }
161 }
162 else return -1;
163 }
164 }
165 if(inflateEnd(&d_stream) != Z_OK) return -1;
166 *ndata = d_stream.total_out;
167 return 0;
168 }
169 #ifdef _DEBUG_ZSTREAM
170 #define BUF_SIZE 65535
171 int main()
172 {
173   char *data = "kjdalkfjdflkjdlkfjdklfjdlkfjlkdjflkdjflddajfkdjfkdfaskf;ldsfk;ldakf;ldskfl;dskf;ld";
174 uLong ndata = strlen(data);
175 Bytef zdata[BUF_SIZE];
176 uLong nzdata = BUF_SIZE;
177 Bytef odata[BUF_SIZE];
178 uLong nodata = BUF_SIZE;
179 memset(zdata, 0, BUF_SIZE);
180 //if(zcompress((Bytef *)data, ndata, zdata, &nzdata) == 0)
181 if(gzcompress((Bytef *)data, ndata, zdata, &nzdata) == 0)
182 {
183   fprintf(stdout, "nzdata:%d %s\n", nzdata, zdata);
184   memset(odata, 0, BUF_SIZE);
185   //if(zdecompress(zdata, ndata, odata, &nodata) == 0)
186   if(gzdecompress(zdata, ndata, odata, &nodata) == 0)
187   {
188     fprintf(stdout, "%d %s\n", nodata, odata);
189   }
190   }
191 }
192 #endif

 一个使用zlib的类的实现

  1 #pragma once
  2 #include <conio.h>
  3 #include <zlib.h>
  4 #include <stdlib.h>
  5 #include <string.h>
  6 #include <errno.h>
  7 #include <stdio.h>
  8 
  9 #include <iostream>
 10 using namespace std;
 11 
 12 #define WINDOWS_PLATFORM
 13 
 14 class Mlib
 15 {
 16 public:
 17     Mlib() {}
 18     ~Mlib() {}
 19     int Compress(char * DestName, const char *SrcName);
 20     int UnCompress(char * DestName, const char *SrcName);
 21 };
 22 
 23 int Mlib::Compress(char * DestName, const char *SrcName)
 24 {
 25     char SourceBuffer[102400] = { 0 };  //压缩文件时的源buffer
 26 
 27     FILE* fp;  //打开欲压缩文件时文件的指针
 28     FILE* fp1;  //创建压缩文件时的指针 
 29 
 30     errno_t err; //错误变量的定义
 31 #ifdef WINDOWS_PLATFORM
 32     err = fopen_s(&fp, SrcName, "r+b");//打开欲压缩的文件
 33     if (err)
 34     {
 35         printf("文件打开失败! \n");
 36         return 1;
 37     }
 38 #endif 
 39 #ifdef    WINDOWS_CE_PLATFORM
 40     fp = fopen_s(SrcName, "r+b");//打开欲压缩的文件
 41     if (fp)
 42     {
 43         printf("文件打开失败! \n");
 44         return 1;
 45     }
 46 
 47 #endif 
 48 
 49 
 50     //获取文件长度
 51     long cur = ftell(fp);
 52     fseek(fp, 0L, SEEK_END);
 53     long fileLength = ftell(fp);
 54     fseek(fp, cur, SEEK_SET);
 55 
 56 
 57     //读取文件到buffer
 58     fread(SourceBuffer, fileLength, 1, fp);
 59     fclose(fp);
 60 
 61     //压缩buffer中的数据
 62     uLongf SourceBufferLen = 102400;
 63     char* DestBuffer = (char*)::calloc((uInt)SourceBufferLen, 1);
 64     err = compress((Bytef*)DestBuffer, (uLongf*)&SourceBufferLen, (const Bytef*)SourceBuffer, (uLongf)fileLength);
 65     if (err != Z_OK)
 66     {
 67         cout << "压缩失败:" << err << endl;
 68         return 1;
 69     }
 70 
 71     //创建一个文件用来写入压缩后的数据
 72     err = fopen_s(&fp1, DestName, "w+b");
 73     if (!fp1)
 74     {
 75         printf("压缩文件创建失败! \n");
 76         return 1;
 77     }
 78 
 79     fwrite(DestBuffer, SourceBufferLen, 1, fp1);
 80     fclose(fp1);
 81     return 0;
 82 }
 83 
 84 int Mlib::UnCompress(char * DestName,const char *SrcName)
 85 {
 86     char uSorceBuffer[102400] = { 0 };  //解压缩文件时的源buffer
 87     FILE* fp3;  //打开欲解压文件的文件指针
 88     FILE* fp4;  //创建解压文件的文件指针
 89     errno_t err; //错误变量的定义
 90                  //打开欲解压的文件
 91     err = fopen_s(&fp3, SrcName, "r+b");
 92     if (err)
 93     {
 94         printf("文件打开失败! \n");
 95         return 1;
 96     }
 97 
 98     //获取欲解压文件的大小
 99     long ucur = ftell(fp3);
100     fseek(fp3, 0L, SEEK_END);
101     long ufileLength = ftell(fp3);
102     fseek(fp3, ucur, SEEK_SET);
103 
104 
105     //读取文件到buffer
106     fread(uSorceBuffer, ufileLength, 1, fp3);
107     fclose(fp3);
108 
109     uLongf uDestBufferLen = 1024000;//此处长度需要足够大以容纳解压缩后数据
110     char* uDestBuffer = (char*)::calloc((uInt)uDestBufferLen, 1);
111     //解压缩buffer中的数据
112     err = uncompress((Bytef*)uDestBuffer, (uLongf*)&uDestBufferLen, (Bytef*)uSorceBuffer, (uLongf)ufileLength);
113 
114     if (err != Z_OK)
115     {
116         cout << "解压缩失败:" << err << endl;
117         return 1;
118     }
119 
120     //创建一个文件用来写入解压缩后的数据
121     err = fopen_s(&fp4, DestName, "wb");
122     if (err)
123     {
124         printf("解压缩文件创建失败! \n");
125         return 1;
126     }
127 
128     printf("写入数据... \n");
129     fwrite(uDestBuffer, uDestBufferLen, 1, fp4);
130     fclose(fp4);
131     return 0;
132 }

 

 

posted @ 2016-04-14 17:46  阆苑小书童  阅读(1182)  评论(0编辑  收藏  举报