Zlib Practice

来源:互联网 发布:vs2010mfc编程入门 编辑:程序博客网 时间:2024/05/01 16:12
开源代码:http://www.zlib.net/
zlib使用手册:http://www.zlib.net/manual.html
zlib wince版:http://www.tenik.co.jp/~adachi/wince/

在这里,你可以查看基于各种操作系统平台的压缩与解缩代码实现。

Compile win32 zlib v1.2.7 using vs2010

1. 下载

 http://zlib.net/zlib-1.2.7.tar.gz

2、编译

打开 vs2010 tools里的 command prompt

cd 到 zlib-1.2.7 目录下 

nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" OBJA="match686.obj inffas32.obj"

注: 

这边编译的是32位的, 方法来自于zlib-1.2.7\contrib\masmx86\readme.txt。
编译64的方法, 可以参考 zlib-1.2.7\contrib\masmx64\readme.txt 中的Build instructions。
亦可以按照zlib-1.2.7\contrib\vstudio中 readme.txt的方法

目录下会产生 zlib.lib zdll.lib  zlib1.dll


4. 用zlib能干什么

  先来看看 zlib 都提供了那些函数, 都在zlib.h中,看到一堆宏不要晕,其实都是为了兼容各种编译器和一些类型定义.死死抓住那些主要的函数的原型声明就不会受到这些东西的影响了.

  关键的函数有那么几个:

  (1)int compress (Bytef *dest,  uLongf *destLen, const Bytef *source, uLong sourceLen);

  把源缓冲压缩成目的缓冲, 就那么简单, 一个函数搞定

  (2) int compress2 (Bytef *dest,  uLongf *destLen,const Bytef *source, uLong sourceLen,int level);

  功能和上一个函数一样,都一个参数可以指定压缩质量和压缩数度之间的关系(0-9)不敢肯定这个参数的话不用太在意它,明白一个道理就好了: 要想得到高的压缩比就要多花时间

  (3) uLong compressBound (uLong sourceLen);

  计算需要的缓冲区长度. 假设你在压缩之前就想知道你的产度为 sourcelen 的数据压缩后有多大, 可调用这个函数计算一下,这个函数并不能得到精确的结果,但是它可以保证实际输出长度肯定小于它计算出来的长度

  (4) int uncompress (Bytef *dest,  uLongf *destLen,const Bytef *source, uLong sourceLen);

  解压缩(看名字就知道了:)

  (5) deflateInit() + deflate() + deflateEnd()

  3个函数结合使用完成压缩功能,具体用法看 example.c 的 test_deflate()函数. 其实 compress() 函数内部就是用这3个函数实现的(工程 zlib 的 compress.c 文件)

  (6) inflateInit() + inflate() + inflateEnd()

  和(5)类似,完成解压缩功能.

  (7) gz开头的函数. 用来操作*.gz的文件,和文件stdio调用方式类似. 想知道怎么用的话看example.c 的 test_gzio() 函数,很easy.

  (8) 其他诸如获得版本等函数就不说了.

  总结: 其实只要有了compress() 和uncompress() 两个函数,在大多数应用中就足够了.

  题外话: 我最初看到zlib的源代码时被好多宏吓倒了,呵呵,后来仔细看下去才发现原来接口那么简单. 至于那些英文说明也没想象中的那么难懂.只要有尝试的勇气,总能有些收获.


以下是经过测试的 WinCE 及 WinXP 下的代码

第一步: 首先到http://www.zlib.net/下载个ZLIB,
             WinXP: 解压缩后打开zlib-1.2.3\projects\visualc6\zlib.dsw,选择Win32 LIB Release 按F7编绎生成zlib.lib, zlib.dll.
            WinCE: 下载一个for Windows CE 版的包,里面针对各种平台(ARM4, ARM4I, MIPS, X86)有对应的zlibce.dll zlibce.lib.

第二步: 建立EVC 或者 VS2005 的对话框工程.
             在工程中添加以下文件:zlib.h, zconf.h, zlib.lib, zlib.dll (或者 zlibce.dll);
            这3个文件就在刚才从http://www.zlib.net/下载的软件包中.

第三步: 包含头文件
#include "zlib.h"

主要使用fopen等C标准接口实现的,只用到zlib的Compress()和UnCompress()接口;里面的条件编译是针对PC和WCE的

封装的类:

class CZlib{public: CZlib(); ~ CZlib(); int Compress(char * DestName,const char *SrcName); int UnCompress(char * DestName,const char *SrcName);};

接口实现:

压缩

int CZlib::Compress(char * DestName,const char *SrcName){    char SourceBuffer[102400] = {0};  //压缩文件时的源buffer    FILE* fp;  //打开欲压缩文件时文件的指针    FILE* fp1;  //创建压缩文件时的指针     errno_t err; //错误变量的定义#ifdef WINDOWS_PLATFORM    err = fopen_s(&fp,SrcName,"r+b");//打开欲压缩的文件    if(err)    {        printf("文件打开失败! \n");        return 1;    }#endif #ifdef    WINDOWS_CE_PLATFORM    fp = fopen_s(SrcName,"r+b");//打开欲压缩的文件if(fp)    {        printf("文件打开失败! \n");        return 1;    }#endif         //获取文件长度    long cur = ftell(fp);    fseek(fp,0L,SEEK_END);    long fileLength = ftell(fp);    fseek(fp,cur,SEEK_SET);    //读取文件到buffer    fread(SourceBuffer,fileLength,1,fp);    fclose(fp);    //压缩buffer中的数据    uLongf SourceBufferLen=102400;    char* DestBuffer=(char*)::calloc((uInt)SourceBufferLen, 1);    err=compress((Bytef*)DestBuffer,(uLongf*)&SourceBufferLen,(const Bytef*)SourceBuffer,(uLongf)fileLength);    if(err!=Z_OK)    {        cout<<"压缩失败:"<<err<<endl;        return 1;    }        //创建一个文件用来写入压缩后的数据    err = fopen_s(&fp1, DestName,"w+b");    if(!fp1)    {        printf("压缩文件创建失败! \n");        return 1 ;    }    fwrite(DestBuffer,SourceBufferLen,1,fp1);    fclose(fp1);    return 0;}



解压

int CZlib::UnCompress(char * DestName,const char *SrcName){    char uSorceBuffer[102400] = {0};  //解压缩文件时的源buffer    FILE* fp3;  //打开欲解压文件的文件指针    FILE* fp4;  //创建解压文件的文件指针    errno_t err; //错误变量的定义    //打开欲解压的文件    err = fopen_s(&fp3,SrcName,"r+b");    if(err)    {        printf("文件打开失败! \n");        return 1;    }    //获取欲解压文件的大小    long ucur = ftell(fp3);    fseek(fp3,0L,SEEK_END);    long ufileLength = ftell(fp3);    fseek(fp3,ucur,SEEK_SET);    //读取文件到buffer    fread(uSorceBuffer,ufileLength,1,fp3);    fclose(fp3);    uLongf uDestBufferLen=1024000;//此处长度需要足够大以容纳解压缩后数据    char* uDestBuffer=(char*)::calloc((uInt)uDestBufferLen, 1);    //解压缩buffer中的数据    err=uncompress((Bytef*)uDestBuffer,(uLongf*)&uDestBufferLen,(Bytef*)uSorceBuffer,(uLongf)ufileLength);    if(err!=Z_OK)    {        cout<<"解压缩失败:"<<err<<endl;        return 1;    }    //创建一个文件用来写入解压缩后的数据    err = fopen_s(&fp4,DestName,"wb");    if(err)    {        printf("解压缩文件创建失败! \n");        return 1 ;    }    printf("写入数据... \n");    fwrite(uDestBuffer,uDestBufferLen,1,fp4);    fclose(fp4);    return 0;}


测试代码:

test.Compress("1.zip","test.docx");

test.UnCompress("11.docx","1.zip");

 

上述代码对于大文件就不适合了,因为是一次读出,一次写入的,下面是针对大文件的改进,分批读,分批写,代码如下:

WF_Error CZlib::Compress(const char * DestName,const char *SrcName){    FILE * fp_in = NULL;int len = 0;char buf[16384];    WF_Error re = WF_OK;        if( NULL == (fp_in = fopen(SrcName,"rb")))    {        return WF_FAIL;    }    /////////////////////////////////////////////    gzFile out = gzopen(DestName,"wb6f");        if(out == NULL)    {        return WF_FAIL;    }    for(;;)    {        len = fread(buf,1,sizeof(buf),fp_in);                if(ferror(fp_in))        {            re = WF_FAIL;            break;        }                if(len == 0) break;        if(gzwrite(out, buf, (unsigned)len) != len)        {            re = WF_FAIL;        }    }    gzclose(out);    fclose(fp_in);    return re; } WF_Error CZlib::UnCompress(const char * DestName,const char *SrcName){    FILE * fp_out = NULL;WF_Error re = WF_OK;        gzFile in;int len = 0;char buf[16384];    in = gzopen(SrcName,"rb");    if(in == NULL)    {        return WF_FAIL;    }    if(NULL == (fp_out = fopen(DestName,"wb")))    {        gzclose(in);        return WF_FAIL;    }        for (;;)    {        len = gzread(in,buf,sizeof(buf));        if(len < 0)        {            re = WF_FAIL;            break;        }        if(len == 0) break;        if(fwrite(buf,1,(unsigned)len,fp_out)!=len)        {            re = WF_FAIL;            break;        }    }    fclose(fp_out);    gzclose(in);    return re;}