zlib 是通用的压缩库,提供了一套
in-memory
压缩和解压函数,并能检测解压出来的数据的完整性(integrity)
。
zlib
也支持读写
gzip (.gz)
格式的文件。
linux 下的 zlib 库安装
第一步:zlib 的下载(不建议在共享目录中操作)
wget http : //www.zlib.net/zlib-1.2.11.tar.gz
第二步:解压
tar zxvf zlib-1.2.11.tar.gz
第三步:进入解压好的文件中
cd zlib-1.2.11
第四步:编译-相关参数配置,软件安装位置,支持软件设置,软件依赖检查,生成编译
对应的工具文件。
./configure
第五步:根据 configure 的配置信息生成“二进制文件”
make
第六步:把生成的二进制文件复制到系统指定目录
make install
注意:使用 zlib 中的 api 在编译时要加-lz 指定库文件
数据压缩 API(compress)
头文件:
#include <zlib.h>
函数原型:
int compress(Bytef *dest, uLongf *destLen, const Bytef *source,uLong sourceLen);
作用:
compress 函数将 source 缓冲区中的内容压缩到 dest 缓冲区。sourceLen 表示 source 缓冲
区的大小(以字节计)。注意函数的第二个参数 destLen 是传址调用。当调用函数时,destLen表示 dest 缓冲区的大小,destLen>(sourceLen+12)*100.1%。当函数退出后,destLen 表示压缩后缓冲区的实际大小。此时 destLen/sourceLen 正好是压缩率。
参数含义:
dest: 用来保存压缩后数据的内存地址
destLen:dest 的大小,当函数返回后,该值表示压缩后存入 dest 缓冲区中实际的字节大 小
source:用来保存待压缩的数据
sourceLen:source 空间的大小
返回值:
compress 若成功,则返回 Z_OK;若没有足够内存,则返回 Z_MEM_ERROR;若输出缓冲区不够大,则返回 Z_BUF_ERROR。
#define Z_OK 0#define Z_STREAM_END 1#define Z_NEED_DICT 2#define Z_ERRNO (-1)#define Z_STREAM_ERROR (-2)#define Z_DATA_ERROR (-3)#define Z_MEM_ERROR (-4)#define Z_BUF_ERROR (-5)#define Z_VERSION_ERROR (-6)
数据解压缩 API(uncompress)
头文件:
#include <zlib.h>
函数原型:
int uncompress(Bytef *dest, uLongf *destLen, const Bytef *source,uLong sourceLen);
作用:
uncompress 函数将 source 缓冲区的内容解压缩到 dest 缓冲区。sourceLen 是 source 缓冲 区的大小(以字节计)。注意函数的第二个参数 destLen 是传址调用。当调用函数时,destLe 表示 dest 缓冲区的大小,dest 缓冲区要足以容下解压后的数据。在进行解压缩时,需要提前知道被压缩的数据解压出来会有多大。这就要求在进行压缩之前,保存原始数据的大小(也就是解压后的数据的大小)。这不是 zlib 函数库的功能,需要我们做额外的工作。当函数退出后,destLen 是解压出来的数据的实际大小。
参数含义:
dest: 用来保存解压缩后数据的内存地址
destLen:dest 的大小,当函数返回后,该值表示解压缩后存入 dest 缓冲区中实际的字节大小
source:用来保存待解压缩的数据
sourceLen:source 空间的大小
返回值:
uncompress 若成功,则返回 Z_OK ;若没有足够内存,则返回 Z_MEM_ERROR;若输出缓冲区不够大,则返回 Z_BUF_ERROR。若输入数据有误,则返回 Z_DATA_ERROR。
压缩长度预测 API(compressBound)
头文件:
#include <zlib.h>
函数原型:
unsigned long compressBound(unsigned long sourceLen);
作用:
compressBound 函数可以对 compress 压缩后的数据做一个最大大小预估,因为有可能压缩
后的数据比压缩前的数据要大,所以防止在创建保存压缩数据空间时造成的空间不足的问题,就有了空间预估的操作。
参数含义:
sourceLen: 待压缩的数据的长度
返回值:
返回压缩后最大的数据长度
使用示例
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <zlib.h>
int main(int argc, char* argv[])
{
char text[] = "zlib compress and uncompress test\nturingo@163.com\n2012-11-05\n";
uLong tlen = strlen(text) + 1; /* 需要把字符串的结束符'\0'也一并处理 */
char* buf = NULL;
uLong blen;
/* 计算缓冲区大小,并为其分配内存 */
blen = compressBound(tlen); /* 压缩后的长度是不会超过 blen 的 */
if((buf = (char*)malloc(sizeof(char) * blen)) == NULL)
{
printf("no enough memory!\n");
return -1;
}
/* 压缩 */
if(compress(buf, &blen, text, tlen) != Z_OK)
{
printf("compress failed!\n");
return -1;
}
/* 解压缩 */
if(uncompress(text, &tlen, buf, blen) != Z_OK)
{
printf("uncompress failed!\n");
return -1;
}
/* 打印结果,并释放内存 */
printf("%s", text);
if(buf != NULL)
{
free(buf);
buf = NULL;
}
printf("源数据长度:%ld\n",tlen);
printf("压缩后数据长度:%ld\n",blen);
printf("压缩率%f%%\n",(float)blen/(float)tlen*100);
return 0;
}
gzip(.gz)文件打开函数(gzopen)
头文件:
#include <zlib.h>
函数原型:
gzFile gzopen(const char *path, const char *mode);
作用:
以 mode 方式打开名为 path 一个 gzip 压缩文件(.gz)。
参数含义:
path: gzip 文件的名字
mode:打开方式,和 fopen 的参数相同
返回值:
成功返回一个 gzFile 流指针,不用去在意 gzFile 是啥,它是一个文件流结构体,和
File 差不多,失败返回 NULL
typedef struct gzFile_s * gzFile ; /* semi-opaque gzip file descriptor */
gzip(.gz)文件关闭函数(gzclose)
头文件:
#include <zlib.h>
函数原型:
int gzclose(gzFile file);
作用:
关闭 file 文件流指向的压缩文件。
参数含义:
file: gzFile 文件流
返回值:
成功返回 Z_OK, 如果文件无效,gzclose 将返回 Z_STREAM_ERROR(-2), Z_ERRNO()(文 件操作错误),Z_MEM_ERROR(内存不足),Z_BUF_ERROR(最后一次读取在 gzip 流中结束)
gzip(.gz)文件写函数
gzputc 函数
头文件:
#include <zlib.h>
函数原型:
int gzputc(gzFile file, int c);
作用:
将字符 c 写入压缩文件流 file 中
参数含义:
file: gzFile 文件流
c:待写入的字符数据(ASCII 码形式)
返回值:
成功返回写入的字符,失败返回-1
gzputs 函数
头文件:
#include <zlib.h>
函数原型:
int gzputs(gzFile file, const char *s);
作用:
将字符串 s 写入压缩文件流 file 中。
参数含义:
file: gzFile 文件流
s:待写入的字符串数据
返回值:
成功返回写入的字符数,失败返回-1
gzprintf 函数
头文件:
#include <zlib.h>
函数原型:
int gzprintf(gzFile file, const char *format, ...);
作用:
将格式化字符串 format 写入压缩文件流 file 中。
参数含义:
file: gzFile 文件流
format:待写入的格式化字符串数据
返回值:
成功返回写入的字符数,失败返回-1
gzwrite 函数
头文件:
#include <zlib.h>
函数原型:
int gzwrite(gzFile file,voidpc buf, unsigned len);
作用:
将 buf 内存的前 len 个字节写入 file 流中。
参数含义:
file: gzFile 文件流
buf:待写入的内存数据
len:待写入的字节数
返回值:
成功返回实际写入的字符数,失败返回-1
gzip(.gz)文件读函数
gzgetc 函数
头文件:
#include <zlib.h>
函数原型:
int gzgetc(gzFile file);
作用:
从 file 流指向的压缩文件中读取一个字符,返回它的 ASCII 码
参数含义:
file: gzFile 文件流
返回值:
成功返回读取字符的 ASCII 码,失败返回-1
gzgets 函数
头文件:
#include <zlib.h>
函数原型:
int gzgets(gzFile file,char *buf, int len);
作用:
从 file 流指向的压缩文件中读取一个字符串
参数含义:
file: gzFile 文件流
buf:保存字符串的空间地址
len:读取字符串的长度
返回值:
成功返回实际读取字符的个数,失败返回-1
gzread 函数
头文件:
#include <zlib.h>
函数原型:
int gzgets(gzFile file, voidp buf, unsigned len);
作用:
从 file 流指向的压缩文件中读取一个 len 个字节数据放到 buf 指向的内存中
参数含义:
file: gzFile 文件流
buf:保存数据的空间地址
len:读取数据的字节长度
返回值:
成功返回实际读取字符的个数,失败返回-1
gzip(.gz)文件指针定位函数
gztell 函数
头文件:
#include <zlib.h>
函数原型:
int gztell(gzFile file);
作用:
返回 file 流指向的文件指针距离文件开头位置的距离
参数含义:
file: gzFile 文件流
返回值:
返回文件指针距离文件开头的字节数,失败返回-1
gzseek 函数
头文件:
#include <zlib.h>
函数原型:
z_off_t gzseek(gzFile file,z_off_t offset, int whence);
作用:
指定 file 指向的文件指针基于 whence 偏移 offset 个字节
参数含义:
file: gzFile 文件流
offset:偏移量
whence:偏移起始位置
SEEK_SET:基于文件开头定位
SEEK_CUR:基于当前位置定位
SEEK_END:基于文件末尾定位
返回值:
成功返回文件开头距离现在位置的字节数,失败返回-1
备注:
z_off_t 是有符号长整型
gzrewind 函数
头文件:
#include <zlib.h>
函数原型:
int gzrewind(gzFile file);
作用:
将 file 指向的文件指针偏移到文件开头
参数含义:
file: gzFile 文件流
返回值:
忽略
使用示例
#include <stdio.h>
#include <string.h>
#include <zlib.h>
unsigned long file_size(char *filename) //计算文件大小
{
FILE *pFile = fopen(filename, "rb");
fseek(pFile, 0, SEEK_END); //偏移到文件尾
unsigned long size = ftell(pFile); //读取文件指针到开头的字节数
fclose(pFile);
return size;
}
int decompress_one_file(char *infilename, char *outfilename)
{
int num_read = 0;
char buffer[128] = {0};
gzFile infile = gzopen(infilename, "rb");
FILE *outfile = fopen(outfilename, "wb");
if (!infile || !outfile)
{
return -1;
}
while ((num_read = gzread(infile, buffer, sizeof(buffer))) > 0)
{
fwrite(buffer, 1, num_read, outfile);
memset(buffer,0,128);
}
gzclose(infile);
fclose(outfile);
return 0;
}
int compress_one_file(char *infilename, char *outfilename)
{
int num_read = 0; //保存读取到的字节数
char inbuffer[128] = {0}; //保存读取的文件数据
unsigned long total_read = 0; //保存源文件大小
FILE *infile = fopen(infilename, "rb");
gzFile outfile = gzopen(outfilename, "wb");
if (!infile || !outfile)
{
return -1;
}
while((num_read = fread(inbuffer, 1, sizeof(inbuffer), infile)) > 0) //读文件数据
{
total_read += num_read;
gzwrite(outfile, inbuffer, num_read); //写到压缩文件中
memset(inbuffer,0,128); //清空内存
}
fclose(infile); //关闭文件
gzclose(outfile); //关闭压缩文件
printf("原文件大小: %ld bytes\n 压缩后的文件大小: %ld bytes\n 压缩率 %4.2f%%\n",total_read, file_size(outfilename),(1.0-
file_size(outfilename)*1.0/total_read)*100.0);
return 0;
}
int main(int argc, char **argv)
{
compress_one_file(argv[1],argv[2]); //压缩文件 argv[1]是待压缩文件名,grgv[2]是压缩文件名
//decompress_one_file(argv[1],argv[2]); //解压文件 argv[1]是压缩文件名,grgv[2]是解压后的文件名
return 0;
}