Zlib实现压缩和解压缩流程

压缩流程:

1.使用zlib做压缩,先调用deflateInit(),这个函数必须在使用deflate之前,zalloc,zfree和opaque等字段都是在deflateInit被初始化的,deflateInit将分配按照顺序分配内存空间,每次分配256K

2.deflateInit有-1 到 9的几个压缩级别,低压缩级别可以获得更快的执行,但是压缩比例低,Z_DEFAULT_COMPRESSION为-1,平衡压缩比例与 速度可以把Level设为6,Level 0实际上没有压缩.另外你也可以使用deflateInit2()来代替DeflateInit().

3.设计一个循环压缩数据,里面只掉用一次deflate(),并且在循环末尾检测是否到达文件底部.

4.读入文件,读入的byte量放到avail_in里面,next_in存放指向这些的字节的指针,使用feof()检测是否到底,为了防止发生任何内存泄漏,请使用delateEnd()

5.内部循环将我们读入的数据压缩,当没有数据可以压缩的时候,avail_in里面的值为0.

6.avail_out指向压缩数据量大小,next_out指向压缩的数据

7.调用deflate(),该函数第二个参数如果为Z_NO_FLUSH的时候数据处于压缩状态,一但为Z_FINISH,deflate()将把压缩数据传到输出流,deflate的返回值为Z_OK和Z_STREAM_END是正确的

解压缩流程:
1.初始化z_stream与压缩过程相同,但是不用设定压缩level,avail_in和next_in需要在inflateInit()之前初始化
2.读入数据填充strm结构,如果到达文件尾跳出外围循环并报告一个Error
3.内层循环实现与压缩相同的功能,将所有输入数据解压成输出数据

4.调用inflate()函数,这里不需要调整flush参数,但要注意inflate的返回值.

#include "zconf.h"
#include "zlib.h"
#include <string.h>
// The one and only application object
CWinApp theApp ;
using namespace std ;
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
#  include <fcntl.h>
#  include <io.h>
#  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
#else
#  define SET_BINARY_MODE(file)
#endif
#define CHUNK 16384
int def(FILE*source,FILE*dest,int level)
{
    int ret,flush ;
    unsigned have ;
    z_stream strm ;
    unsigned char in[CHUNK];
    unsigned char out[CHUNK];
    /*allocate defalte state*/
    strm.zalloc=Z_NULL ;
    strm.zfree=Z_NULL ;
    strm.opaque=Z_NULL ;
    ret=deflateInit(&strm,level);
    if(ret!=Z_OK)
    return ret ;
    
    do 
    {
        strm.avail_in=fread(in,1,CHUNK,source);
        if(ferror(source))
        {
            (void)deflateEnd(&strm);
            return Z_ERRNO ;
        }
        flush=feof(source)?Z_FINISH:Z_NO_FLUSH ;
        strm.next_in=in ;
        do 
        {
            strm.avail_out=CHUNK ;
            strm.next_out=out ;
            ret=deflate(&strm,flush);
            have=CHUNK-strm.avail_out ;
            if(fwrite(out,1,have,dest)!=have||ferror(dest))
            {
                (void)deflateEnd(&strm);
                return Z_ERRNO ;
            }
            //The way we tell that deflate() has no more output is by seeing that it did not fill the output
            buffer,
            //leaving avail_out greater than zero.
        }
        while(strm.avail_out==0);
    }
    while(flush!=Z_FINISH);
    (void)deflateEnd(&strm);
    return Z_OK ;
}
int inf(FILE*source,FILE*dest)
{
    int ret ;
    unsigned have ;
    z_stream strm ;
    unsigned char in[CHUNK];
    unsigned char out[CHUNK];
    strm.zalloc=Z_NULL ;
    strm.zfree=Z_NULL ;
    strm.opaque=Z_NULL ;
    strm.avail_in=0 ;
    strm.next_in=Z_NULL ;
    ret=inflateInit(&strm);
    if(ret!=Z_OK)
    return ret ;
    do 
    {
        strm.avail_in=fread(in,1,CHUNK,source);
        if(ferror(source))
        {
            (void)inflateEnd(&strm);
            return Z_ERRNO ;
        }
        if(0==strm.avail_in)
        break ;
        strm.next_in=in ;
        do 
        {
            strm.avail_out=CHUNK ;
            strm.next_out=out ;
            ret=inflate(&strm,Z_NO_FLUSH);
            switch(ret)
            {
                case Z_NEED_DICT :
                ret=Z_DATA_ERROR ;
                case Z_DATA_ERROR :
                case Z_MEM_ERROR :
                (void)inflateEnd(&strm);
                return ret ;
            }
            have=CHUNK-strm.avail_out ;
            if(fwrite(out,1,have,dest)!=have||ferror(dest))
            {
                (void)inflateEnd(&strm);
                return Z_ERRNO ;
            }
        }
        while(strm.avail_out==0);
    }
    while(ret!=Z_STREAM_END);
    (void)inflateEnd(&strm);
    return ret=Z_STREAM_END?Z_OK:Z_DATA_ERROR ;
}
void zerr(int ret)
{
    fputs("zpipe: ",stderr);
    switch(ret)
    {
        case Z_ERRNO :
        if(ferror(stdin))
        fputs("error reading stdin/n",stderr);
        if(ferror(stdout))
        fputs("error writing stdout/n",stderr);
        break ;
        case Z_STREAM_ERROR :
        fputs("invalid compression level/n",stderr);
        break ;
        case Z_DATA_ERROR :
        fputs("invalid or incomplete deflate data/n",stderr);
        break ;
        case Z_MEM_ERROR :
        fputs("out of memory/n",stderr);
        break ;
        case Z_VERSION_ERROR :
        fputs("zlib version mismatch!/n",stderr);
    }
}
int _tmain(int argc,TCHAR*argv[],TCHAR*envp[])
{
    int nRetCode=0 ;
    // initialize MFC and print and error on failure
    if(!AfxWinInit(:: GetModuleHandle(NULL),NULL,:: GetCommandLine(),0))
    {
        // TODO: change error code to suit your needs
        _tprintf(_T("Fatal Error: MFC initialization failed/n"));
        nRetCode=1 ;
    }
    else 
    {
        // TODO: code your application's behavior here.
    }
    int ret ;
    SET_BINARY_MODE(stdin);
    SET_BINARY_MODE(stdout);
    if(argc==1)
    {
        ret=def(stdin,stdout,Z_DEFAULT_COMPRESSION);
        if(ret!=Z_OK)
        zerr(ret);
        return ret ;
    }
    else if(argc==2&&strcmp(argv[1],"-d")==0)
    {
        ret=inf(stdin,stdout);
        if(ret!=Z_OK)
        zerr(ret);
        return ret ;
    }
    else 
    {
        fputs("zpipe usage: zpipe [-d] < source > dest/n",stderr);
    }
    return nRetCode ;
}
Zlib的deflate, z_stream结构的使用
 
使用deflate进行压缩时,先要定义z_stream结构体,
先将z_stream的zalloc, zfree, opaque偏量设为Z_NULL, 再调用
deflateInit函数初始化z_stream结构,初始化时主要是用z_stream结构与Z_DEFAULT_COMPRESSION和默认压缩来初始化,
 
初始化好后,再要初始化四个重要分量,为被压缩源字符串next_in,被压源字符串的长度avail_in,压缩后字符串的最大长度(avail_out),压缩后字符串的存放缓冲区(next_out)。
 
     设好后,还得设一个参数即刷新方式flush, 这个参数是deflate函数的第二个参数,一般设为Z_FINISH, 或者Z_NO_FLUSH, 如果是读的文件取字符串
可以使用flush = feof(source) ? Z_FINISH : Z_NO_FLUSH再设定。
 
    以z_stream, flush为参数,调用deflate函数后,这时开始的next_out指向的内存中就有压缩的字符串了,但next_out, avail_out都会发生变化,其具体的变化是,avail_out会变为剩下的还没有使用的最大空间数,而next_out是指的原来的原来的指针加上所读的字符串,
 
压缩后,可以通过最大压缩后所以空间大小减avail_out得压缩后串大小,通过原来的压缩串指针得压缩后字符串。
如果有任何错误,调用deflateEnd函数,当avail_out等于零时,表示加密串满了,则还要压,不过一般不可能因为压缩串不可能大于源串,如果加密串没满,那么,确认一下avail_in是否为0, 表示把源串全压了,再通过flush的值判断是否再压。
 

以上完成了一次压缩

更多细节:http://www.zlib.net/zlib_how.html

你可能感兴趣的:(Zlib实现压缩和解压缩流程)