zlib是提供数据压缩用 的函式库,由Jean-loup Gailly与Mark Adler所开发,初版0.9版在1995年5月1日发表。zlib使用DEFLATE算法,最初是为libpng函式库所写的,后来普遍为许多软件所使 用。此函式库为自由软件,使用zlib授权。截至2007年3月,zlib是包含在Coverity的美国国土安全部赞助者选择继续审查的开源项目。
特性
数据头(header)
zlib能使用一个gzip数据头,zlib数据头或者不使用数据头压缩数据。
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来压缩和远端仓库的通讯流量。
因为其代码的可移植性,宽松的许可以及较小的内存占用,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 }