zlib数据压缩库

联合创作 · 2023-09-29 15:59

zlib 软件包包含 zlib 库,很多程序中的压缩或者解压缩函数都会用到这个库。zlib 适用于数据压缩的函式库,几乎适用于任何计算器硬件和操作系统。

特性:

  • 数据头(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)被写入到压缩后的数据流中,那么错误数据是可以被跳过的,并且解压缩将重新同步到下个全刷新点。(错误数据的无错恢复被提供)。全刷新点技术对于在不可靠的通道上的大数据流是很有用的,一些过去的数据丢失是不重要的(例如多媒体数据),但是建立太多的全刷新点会极大的影响速度和压缩。

 

  • 数据长度

对于压缩和解压缩,没有数据长度的限制

重复调用库函数允许处理无限的数据块。一些辅助代码(计数变量)可能会溢出,但是不影响实际的压缩和解压缩。

当压缩一个长(无限)数据流时,最好写入全刷新点。

 

使用范例

以下代码可直接用于解压 HTTP gzip

#include <stdlib.h>

#include <string.h>

#include <errno.h>

#include <zlib.h>

/* Compress data */

int zcompress(Bytef *data, uLong ndata,

Bytef *zdata, uLong *nzdata)

{

z_stream c_stream;

int err = 0;

if(data && ndata > 0)

{

c_stream.zalloc = (alloc_func)0;

c_stream.zfree = (free_func)0;

c_stream.opaque = (voidpf)0;

if(deflateInit(&c_stream, Z_DEFAULT_COMPRESSION) != Z_OK) return -1;

c_stream.next_in = data;

c_stream.avail_in = ndata;

c_stream.next_out = zdata;

c_stream.avail_out = *nzdata;

while (c_stream.avail_in != 0 && c_stream.total_out < *nzdata)

{

if(deflate(&c_stream, Z_NO_FLUSH) != Z_OK) return -1;

}

if(c_stream.avail_in != 0) return c_stream.avail_in;

for (;;) {

if((err = deflate(&c_stream, Z_FINISH)) == Z_STREAM_END) break;

if(err != Z_OK) return -1;

}

if(deflateEnd(&c_stream) != Z_OK) return -1;

*nzdata = c_stream.total_out;

return 0;

}

return -1;

}

/* Compress gzip data */

int gzcompress(Bytef *data, uLong ndata,

Bytef *zdata, uLong *nzdata)

{

z_stream c_stream;

int err = 0;

if(data && ndata > 0)

{

c_stream.zalloc = (alloc_func)0;

c_stream.zfree = (free_func)0;

c_stream.opaque = (voidpf)0;

if(deflateInit2(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,

-MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK) return -1;

c_stream.next_in = data;

c_stream.avail_in = ndata;

c_stream.next_out = zdata;

c_stream.avail_out = *nzdata;

while (c_stream.avail_in != 0 && c_stream.total_out < *nzdata)

{

if(deflate(&c_stream, Z_NO_FLUSH) != Z_OK) return -1;

}

if(c_stream.avail_in != 0) return c_stream.avail_in;

for (;;) {

if((err = deflate(&c_stream, Z_FINISH)) == Z_STREAM_END) break;

if(err != Z_OK) return -1;

}

if(deflateEnd(&c_stream) != Z_OK) return -1;

*nzdata = c_stream.total_out;

return 0;

}

return -1;

}

/* Uncompress data */

int zdecompress(Byte *zdata, uLong nzdata,

Byte *data, uLong *ndata)

{

int err = 0;

z_stream d_stream; /* decompression stream */

d_stream.zalloc = (alloc_func)0;

d_stream.zfree = (free_func)0;

d_stream.opaque = (voidpf)0;

d_stream.next_in = zdata;

d_stream.avail_in = 0;

d_stream.next_out = data;

if(inflateInit(&d_stream) != Z_OK) return -1;

while (d_stream.total_out < *ndata && d_stream.total_in < nzdata) {

d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */

if((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END) break;

if(err != Z_OK) return -1;

}

if(inflateEnd(&d_stream) != Z_OK) return -1;

*ndata = d_stream.total_out;

return 0;

}

/* HTTP gzip decompress */

int httpgzdecompress(Byte *zdata, uLong nzdata,

Byte *data, uLong *ndata)

{

int err = 0;

z_stream d_stream = {0}; /* decompression stream */

static char dummy_head[2] =

{

0x8 + 0x7 * 0x10,

(((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,

};

d_stream.zalloc = (alloc_func)0;

d_stream.zfree = (free_func)0;

d_stream.opaque = (voidpf)0;

d_stream.next_in = zdata;

d_stream.avail_in = 0;

d_stream.next_out = data;

if(inflateInit2(&d_stream, 47) != Z_OK) return -1;

while (d_stream.total_out < *ndata && d_stream.total_in < nzdata) {

d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */

if((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END) break;

if(err != Z_OK )

{

if(err == Z_DATA_ERROR)

{

d_stream.next_in = (Bytef*) dummy_head;

d_stream.avail_in = sizeof(dummy_head);

if((err = inflate(&d_stream, Z_NO_FLUSH)) != Z_OK)

{

return -1;

}

}

else return -1;

}

}

if(inflateEnd(&d_stream) != Z_OK) return -1;

*ndata = d_stream.total_out;

return 0;

}

/* Uncompress gzip data */

int gzdecompress(Byte *zdata, uLong nzdata,

Byte *data, uLong *ndata)

{

int err = 0;

z_stream d_stream = {0}; /* decompression stream */

static char dummy_head[2] =

{

0x8 + 0x7 * 0x10,

(((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,

};

d_stream.zalloc = (alloc_func)0;

d_stream.zfree = (free_func)0;

d_stream.opaque = (voidpf)0;

d_stream.next_in = zdata;

d_stream.avail_in = 0;

d_stream.next_out = data;

if(inflateInit2(&d_stream, -MAX_WBITS) != Z_OK) return -1;

//if(inflateInit2(&d_stream, 47) != Z_OK) return -1;

while (d_stream.total_out < *ndata && d_stream.total_in < nzdata) {

d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */

if((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END) break;

if(err != Z_OK )

{

if(err == Z_DATA_ERROR)

{

d_stream.next_in = (Bytef*) dummy_head;

d_stream.avail_in = sizeof(dummy_head);

if((err = inflate(&d_stream, Z_NO_FLUSH)) != Z_OK)

{

return -1;

}

}

else return -1;

}

}

if(inflateEnd(&d_stream) != Z_OK) return -1;

*ndata = d_stream.total_out;

return 0;

}

#ifdef _DEBUG_ZSTREAM

#define BUF_SIZE 65535

int main()

{

char *data = "kjdalkfjdflkjdlkfjdklfjdlkfjlkdjflkdjflddajfkdjfkdfaskf;ldsfk;ldakf;ldskfl;dskf;ld";

uLong ndata = strlen(data);

Bytef zdata[BUF_SIZE];

uLong nzdata = BUF_SIZE;

Bytef odata[BUF_SIZE];

uLong nodata = BUF_SIZE;

memset(zdata, 0, BUF_SIZE);

//if(zcompress((Bytef *)data, ndata, zdata, &nzdata) == 0)

if(gzcompress((Bytef *)data, ndata, zdata, &nzdata) == 0)

{

fprintf(stdout, "nzdata:%d %s\n", nzdata, zdata);

memset(odata, 0, BUF_SIZE);

//if(zdecompress(zdata, ndata, odata, &nodata) == 0)

if(gzdecompress(zdata, ndata, odata, &nodata) == 0)

{

fprintf(stdout, "%d %s\n", nodata, odata);

}

}

}

#endif

 

浏览 6
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报