• 【VC++技术杂谈008】使用zlib解压zip压缩文件


      最近因为项目的需要,要对zip压缩文件进行批量解压。在网上查阅了相关的资料后,最终使用zlib开源库实现了该功能。本文将对zlib开源库进行简单介绍,并给出一个使用zlib开源库对zip压缩文件进行解压的示例程序。

    1.zlib开源库

      zlib是应用最广泛的压缩与解压缩zip文件的免费开源库,提供了数据压缩与解压缩的函式库。

      zlib中最关键的函数有以下两个:

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

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

      其中,函数compress()用于将源缓冲区数据压缩到目的缓冲区,函数uncompress()用于将源缓冲区数据解压到目的缓冲区。

      由此可见,zlib只是一个针对gzip以及deflate算法的库,用于将一段内存压缩/解压之后放到另一段内存上,这离压缩/解压文件甚至文件夹的目标还很远。但是,它提供了一个叫做minizip的例子给出了操作zip文件的方法。

    2.minizip简介

      minizip是zlib的上层库,它封装了与zip文件相关的操作。

      minizip中与解压缩相关的API有以下几个:

      (1)unzFile unzOpen(const char *path); 

      (2)int unzClose(unzFile file);

      (3)int unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info);

      (4)int unzGoToNextFile(unzFile file);

      (5)int unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, 

    void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize);

      (6)int unzOpenCurrentFile(unzFile file);

      (7)int unzCloseCurrentFile(unzFile file);

      (8)int unzReadCurrentFile(unzFile file, voidp buf, unsigned len);

      有了以上这些API,我们就可以对zip文件进行解压缩了。一个完整的解压过程应该包含以下这些步骤:

      (1)调用unzOpen()函数打开一个zip压缩文件,其参数是zip压缩文件的路径。

      (2)调用unzGetGlobalInfo()函数来获取zip压缩文件的一些信息(如内部文件个数等),这些信息会保存在传入参数pglobal_info中。

      (3)然后开始遍历zip文件中的内部文件,初始时会自动定位到第一个内部文件,处理完一个内部文件后可以使用unzGoToNextFile()函数来跳转到下一个内部文件。

      (4)对于每个内部文件来说,可以先调用unzGetCurrentFileInfo()函数来获取该内部文件信息(如文件的路径、文件大小等),这些信息会保存在传入参数pfile_info中。

      (5)调用unzOpenCurrentFile()函数打开该内部文件。

      (6)调用unzReadCurrentFile()函数读取该内部文件内容。

      (7)该内部文件读取完毕之后,调用unzCloseCurrentFile()函数对内部文件进行关闭。

      (8)zip文件中的所有内部文件遍历完成之后,调用unzClose()函数关闭打开的zip压缩文件。

    3.示例程序

      了解了以上的内容之后,我们就可以编写程序使用zlib以及minizip对zip压缩文件进行解压缩了。

    3.1加载相关的头文件及库文件

      在使用zlib以及minizip之前,我们需要加载相关的头文件及库文件到工程中。需要加载的头文件有zlib.h、unzip.h、zip.h。需要加载的库文件有zlib.lib、minizip.lib。需要添加的动态链接库zlib1.dll。这些文件都可以从网上下载得到。

    1     #include "zlib/zlib.h"
    2     #include "zlib/unzip.h"
    3     #include "zlib/zip.h"
    4     #pragma comment(lib, "zlib.lib")
    5     #pragma comment(lib, "minizip.lib")

    3.2配置工程

      因为zlib以及minizip是用C语言编写的,在VC6.0中使用时,需要对工程进行如下配置,否则会出现编译链接通不过的问题。

      (1)在“工程”、“设置”中选择“连接”标签页,在“分类”中选择输入,在“忽略库”中加入MSVCRT。

      (2)在“工程”、“设置”中选择“C/C++”标签页,在“分类”中选择Code Generation,在“Use run-time library”中选择“Debug Multithreaded DLL”。

      (3)在“工程”、“设置”中选择“C/C++”标签页,在“分类”中选择常规,在“预处理程序定义”中加入_AFXDLL。

    3.3示例程序

      如下的示例程序演示了如何调用minizip中的API对zip文件进行解压。

      1 /*
      2  * 函数功能 :  解压zip文件
      3  * 备    注 : 参数strFilePath表示zip压缩文件的路径
      4  *           参数strTempPath表示要解压到的文件目录
      5  * 作    者 : 博客园 依旧淡然(http://www.cnblogs.com/menlsh/  6  */
      7 void CZlibDemoDlg::UnzipFile(CString strFilePath, CString strTempPath)
      8 {
      9     int nReturnValue;
     10 
     11     //打开zip文件
     12     unzFile unzfile = unzOpen(strFilePath);                    
     13     if(unzfile == NULL)
     14     {
     15         MessageBox("打开zip文件失败!", "提示", MB_OK|MB_ICONWARNING);
     16         return;
     17     }
     18 
     19     //获取zip文件的信息
     20     unz_global_info* pGlobalInfo = new unz_global_info;
     21     nReturnValue = unzGetGlobalInfo(unzfile, pGlobalInfo);
     22     if(nReturnValue != UNZ_OK)
     23     {
     24         MessageBox("获取zip文件信息失败!", "提示", MB_OK|MB_ICONWARNING);
     25         return;
     26     }
     27 
     28     //解析zip文件
     29     unz_file_info* pFileInfo = new unz_file_info;
     30     char szZipFName[MAX_PATH];                            //存放从zip中解析出来的内部文件名
     31     for(int i=0; i<pGlobalInfo->number_entry; i++)
     32     {
     33         //解析得到zip中的文件信息
     34         nReturnValue = unzGetCurrentFileInfo(unzfile, pFileInfo, szZipFName, MAX_PATH, 
     35             NULL, 0, NULL, 0);
     36         if(nReturnValue != UNZ_OK)
     37         {
     38             MessageBox("解析zip文件信息失败!", "提示", MB_OK|MB_ICONWARNING);
     39             return;
     40         }
     41 
     42         //判断是文件夹还是文件
     43         switch(pFileInfo->external_fa)
     44         {
     45         case FILE_ATTRIBUTE_DIRECTORY:                    //文件夹
     46             {
     47                 CString strDiskPath = strTempPath + _T("//") + szZipFName;
     48                 CreateDirectory(strDiskPath, NULL);
     49             }
     50             break;
     51         default:                                        //文件
     52             {
     53                 //创建文件
     54                 CString strDiskFile = strTempPath + _T("//") + szZipFName;
     55                 HANDLE hFile = CreateFile(strDiskFile, GENERIC_WRITE,
     56                     0, NULL, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
     57                 if(hFile == INVALID_HANDLE_VALUE)
     58                 {
     59                     MessageBox("创建文件失败!", "提示", MB_OK|MB_ICONWARNING);
     60                     return;
     61                 }
     62 
     63                 //打开文件
     64                 nReturnValue = unzOpenCurrentFile(unzfile);
     65                 if(nReturnValue != UNZ_OK)
     66                 {
     67                     MessageBox("打开文件失败!", "提示", MB_OK|MB_ICONWARNING);
     68                     CloseHandle(hFile);
     69                     return;
     70                 }
     71 
     72                 //读取文件
     73                 const int BUFFER_SIZE = 4096;
     74                 char szReadBuffer[BUFFER_SIZE];
     75                 while(TRUE)
     76                 {
     77                     memset(szReadBuffer, 0, BUFFER_SIZE);
     78                     int nReadFileSize = unzReadCurrentFile(unzfile, szReadBuffer, BUFFER_SIZE);
     79                     if(nReadFileSize < 0)                //读取文件失败
     80                     {
     81                         MessageBox("读取文件失败!", "提示", MB_OK|MB_ICONWARNING);
     82                         unzCloseCurrentFile(unzfile);
     83                         CloseHandle(hFile);
     84                         return;
     85                     }
     86                     else if(nReadFileSize == 0)            //读取文件完毕
     87                     {
     88                         unzCloseCurrentFile(unzfile);
     89                         CloseHandle(hFile);
     90                         break;
     91                     }
     92                     else                                //写入读取的内容
     93                     {
     94                         DWORD dWrite = 0;
     95                         BOOL bWriteSuccessed = WriteFile(hFile, szReadBuffer, BUFFER_SIZE, &dWrite, NULL);
     96                         if(!bWriteSuccessed)
     97                         {
     98                             MessageBox("读取文件失败!", "提示", MB_OK|MB_ICONWARNING);
     99                             unzCloseCurrentFile(unzfile);
    100                             CloseHandle(hFile);
    101                             return;
    102                         }
    103                     }
    104                 }
    105             }
    106             break;
    107         }
    108         unzGoToNextFile(unzfile);
    109     }
    110 
    111     //关闭
    112     if(unzfile)
    113     {
    114         unzClose(unzfile);
    115     }
    116 }

    3.4运行结果

      调用上述的UnzipFile()方法对某个zip文件进行解压,如图1所示。

    图1 解压zip文件

      解压后,可以看到文件夹123中的内容如图2所示。

    图2 解压后的文件

  • 相关阅读:
    雷锋依然在人间 工厂方法模式
    为别人做嫁衣 代理模式
    穿什么有这么重要? 装饰模式
    437. Path Sum III
    434. Number of Segments in a String
    447. Add Strings
    414. Third Maximum Number
    412. Fizz Buzz
    404. Sum of Left Leaves
    405. Convert a Number to Hexadecimal
  • 原文地址:https://www.cnblogs.com/menlsh/p/4480577.html
Copyright © 2020-2023  润新知