移动开发 架构设计 编程语言 互联网 开发经验 Web前端
开发杂谈 系统运维 研发管理 数据库 云 计 算 Java开发
首页 开发总结 移动开发 编程语言 开发经验 Java开发
 当前位置:首页 > Zlib库对网页中deflate压缩数据的解压 > 正文显示
 最新推荐文章
互斥与临界区的比较 完成端口测试服务器功能的客户端 完成端口服务器源码 POW工作量证明原理
科大迅飞合成发音人列表 CreateFile和ANSI 获取扩展sd卡跟路径 android基础总结 内部存储
Android 获取系统各个目录 Android遍历手机内所有文件 Android权限管理之Perm Android教程 使用Ecli
Android SDK版本和AD 搭建最新版本的Android开发 SetThreadAffinit 直接显示图片
Zlib库对网页中deflate压缩数据的解压   (83)

一般情况下网页请求的头里会有一个Content-Encoding字段来表示该网页启用了压缩算法来提高网页传输效率。一般情况下都是以Gzip或deflate为字段值,实际上是以deflate压缩算法来压缩的数据。工作中偶尔碰见了这样的页面内容没有一个解压的代码还挺麻烦的。
deflate 是最基础的算法,gzip在deflate的rawdata前增加了10个字节的 gzheader,尾部添加了8个字节的校验字节(可选 crc32 和 adler32) 和长度标识字节。
zlib库是一个C++常用的解压zip文件的库,提供了各种各样的接口以供调用。其中,deflate使用inflateInit(),而gzip使用inflateInit2()进行初始化,比 inflateInit()多一个参数: -MAX_WBITS,表示处理raw deflate数据。因为gzip数据中的zlib压缩数据块没有zlib header的两个字节。使用inflateInit2时要求zlib库忽略zlib header。
zlib提供了很多接口,在这些复杂的操作之上封装了最简单的两个接口,compress和uncompress。我们一般直接调用就可以了。
简单介绍下常用的函数:
1、 deflateInit() + deflate() + deflateEnd()
3个函数结合使用完成压缩功能,具体用法看 example.c 的 test_deflate()函数. 其实 compress() 函数内部就是用这3个函数实现的(工程 zlib 的 compress.c 文件)
2、 inflateInit() + inflate() + inflateEnd()
和上面的类似,完成解压缩功能,uncompress()函数的内部实现使用的就是它们
3、uLong compressBound(uLong sourceLen);
计算需要的缓冲区长度,这个函数并不精确的计算压缩后的数据有多长,但是可以保证压缩后的长度不会这个结果还长,便于分配空间。
接下来就是我们最常用的一对函数
4、int compress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
压缩数据,要注意的是压缩后的BUF和大小是要预先分配好的,这也是我们为什么要使用compressBound这个函数的原因。
5、int uncompress (Bytef *dest, uLongf *destLen,const Bytef *source, uLong sourceLen);
解压缩数据,同样的,解压后的BUF大小要预先知道,太小了会解压失败。
一般情况下,compress和uncompress函数足以满足我们的要求。
最后附上解压一个从网页中获取的存有压缩数据的文件的代码:

/*************************************************************************
> File Name: un_zip.cpp
> Author:zeus
> Mail:zuixuewosha@163.com
> Created Time: 2017年06月09日 星期五 16时32分28秒
> useage: a.out src_file dst_file
************************************************************************/

#include
#include
#include

int main(int argc, char* argv[])
{
FILE* file;
unsigned char* src_buf = NULL;
unsigned char* ubuf = NULL;
int failed_number = 0;

/* 通过命令行参数将srcfile文件的数据解压缩后存放到dstfile文件中 */
if(argc < 3)
{
printf("Usage: a.out srcfile dstfile\n");
return -1;
}

if((file = fopen(argv[1], "rb")) == NULL)
{
printf("Can\'t open %s!\n", argv[1]);
return -1;
}
/* 装载源文件数据到缓冲区 */
fseek(file,0,SEEK_END);
unsigned long src_length = ftell(file);
unsigned long dst_length = 65536;
rewind(file);
printf("src_length is %d\n",src_length);
if((src_buf = (unsigned char*)malloc(sizeof(unsigned char) * src_length)) == NULL)
{
printf("No enough memory!\n");
fclose(file);
return -1;
}
fread(src_buf, sizeof(unsigned char), src_length, file);
/* 解压缩数据,失败后分配更大的空间,最大失败次数 10 */
while(failed_number < 10)
{
if((ubuf = (unsigned char*)malloc(sizeof(unsigned char) * dst_length)) == NULL)
{
printf("No enough memory!\n");
fclose(file);
return -1;
}

if(uncompress(ubuf, &dst_length, src_buf, src_length) != Z_OK)
{
printf("Uncompress %s failed,try allocate more space!\n", argv[1]);
free(ubuf);
ubuf = NULL;
/*失败后分配两倍空间*/
dst_length *=2;
failed_number++;
}
else
{
break;
}
}
fclose(file);

if((file = fopen(argv[2], "wb")) == NULL)
{
printf("Can\'t create %s!\n", argv[2]);
return -1;
}
/* 保存解压缩后的数据到目标文件 */
fwrite(ubuf, sizeof(unsigned char), dst_length, file);
fclose(file);

free(src_buf);
free(ubuf);

return 0;
}



=========================================
关于抓取的用gzlib压缩的网页的解压
原创 2011年08月30日 10:17:29 标签:stream /output /buffer /input /up 430
参数source指向的是压缩数据
参数len是压缩数据的长度
参数dest是指向目的的指针的地址
参数gzip为非0表示压缩数据为gzip格式,否则为deflate压缩格式

#define CHUNK 16384
int inflate_read(char *source,int len,char **dest,int gzip) {
int ret;
unsigned have;
z_stream strm;
unsigned char out[CHUNK];
int totalsize = 0;

/* allocate inflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;

if(gzip)
ret = inflateInit2(&strm, 47);
else
ret = inflateInit(&strm);

if (ret != Z_OK)
return ret;

strm.avail_in = len;
strm.next_in = source;

/* run inflate() on input until output buffer not full */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
inflateEnd(&strm);
return ret;
}
have = CHUNK - strm.avail_out;
totalsize += have;
*dest = realloc(*dest,totalsize);
memcpy(*dest + totalsize - have,out,have);
} while (strm.avail_out == 0);

/* clean up and return */
(void)inflateEnd(&strm);
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
 最热文章
http://www.3 获取扩展sd卡跟路径 Android遍历手机内 android基础总结
搭建最新版本的Andro Android 获取系统 Android SDK版 直接显示图片
科大迅飞合成发音人列表 Android教程 使用 Android权限管理之 SetThreadAff
实时视频传输的关键技术 VC++内存泄漏的检测与 Zlib库对网页中def vc, c++ stl
在Visual C++中 VC 获取 程序窗口大小 C++中的STL中map C++中的STL中map
移动开发 架构设计 编程语言 互联网 开发经验 Web前端
开发杂谈 系统运维 研发管理 数据库 云 计 算 Java开发
 网站联系 QQ: 121756557 E-Mail: 121756557@qq.com ©2018