zoukankan      html  css  js  c++  java
  • mfc zlib minizip vs2019

    需要注意Release和Debug使用的dll可能有差异,Release时需要使用对应的Dll

    zlib源码文件中zlib123contribvstudio此文件夹包含所需的zip、unzip相关实例代码minizip
    最新版为zlib1.2.11

    1. 相关库文件
      https://files.cnblogs.com/files/ives/zlibVC.zip

    2. 导入zlib.h,zconf.h

    include "zlib.h"

    include "zconf.h"

    pragma comment(lib,"zlib.lib")

    LNK2001:
    默认调用规则不一致,添加预定义即可

    define ZLIB_WINAPI

    LNK4098: defaultlib "libc.lib" conflicts with use of other libs; use /NODEFAULTLIB:library
    项目->属性中->配置属性->链接器->输入->在忽略特定库中写入打不开的文件的名称libc.lib

    D8016:
    项目”—>“属性”—>“C/C++” “常规”—>“调试信息格式”—>选择“程序数据库(/Zi)”或“无”
    项目”—>“属性”—>“C/C++” 代码生成”—>“启用函数集链接”—>选择“是 (/Gy)”

    LNK1104无法打开libc.lib
    “项目”-->“配置属性->链接器->输入->忽略特定库”后填入“LIBC.lib ”。

    LNK1281 无法生成 SAFESEH 映像
    “项目”-->“配置属性->链接器-命令行 输入 /SAFESEH:NO

    1>unzip.obj : error LNK2019: 无法解析的外部符号_inflateInit2_,该符号在函数_unzOpenCurrentFile3 中被引用
    1>unzip.obj : error LNK2019: 无法解析的外部符号_inflate,该符号在函数_unzReadCurrentFile 中被引用
    1>unzip.obj : error LNK2019: 无法解析的外部符号_crc32,该符号在函数_unzReadCurrentFile 中被引用
    1>zip.obj : error LNK2001: 无法解析的外部符号_crc32
    1>unzip.obj : error LNK2019: 无法解析的外部符号_inflateEnd,该符号在函数_unzCloseCurrentFile 中被引用
    1>zip.obj : error LNK2019: 无法解析的外部符号_get_crc_table,该符号在函数_zipOpenNewFileInZip4_64 中被引用
    1>zip.obj : error LNK2019: 无法解析的外部符号_deflateInit2_,该符号在函数_zipOpenNewFileInZip4_64 中被引用
    1>zip.obj : error LNK2019: 无法解析的外部符号_deflate,该符号在函数_zipWriteInFileInZip 中被引用
    1>zip.obj : error LNK2019: 无法解析的外部符号_deflateEnd,该符号在函数_zipCloseFileInZipRaw64 中被引用

    zconf.h

    # define ZEXPORT WINAPI   替换为           #define ZEXPORT __cdecl
    #define ZEXPORTVA WINAPIV    替换为   #define WINAPIV     __cdecl
    

    解压缩时在inffas32.asm中报错的处理方式&编译时会提示inflate_fast重复定义
    https://www.cnblogs.com/hanford/p/6168837.html
    https://blog.csdn.net/u010810750/article/details/78975325

    1. 在zlib源码的zlibvc工程属性-预处理器定义里面去掉 ASMINF、ASMV 定义,屏蔽掉汇编模块
    2. 打开zlib-1.2.11contribmasmx86下面的汇编文件inffas32.asm,将里面_inflate_fast全部替换成其他任意函数名
    

    zip相关实现
    https://blog.csdn.net/fyyyr/article/details/79252677

    zip解压缩

    1. 将zlib-1.x.xcontribminizip文件夹下除miniunz.c和minizip.c以外的.h与.c文件放到项目目录下,并将zip.h与unzip.h导入到工程中。
    2. 打开需要解压缩的文件
    //传入zip文件的绝对路径,返回一个unzFile对象。这是一个void*指针,用于指向打开的zip文件
    unzFile unzOpen(const char *path);
    

    操作完毕后需要关闭已打开的压缩文件:

    int unzClose OF(unzFile file);
    
    1. 获取zip文件的信息
    int unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info);
    

    传入获取到的unzFile对象,传入一个空的unz_global_info,函数执行完成后,会将zip文件的信息填充到该unz_global_info指针中。

    传入的unz_global_info定义如下:

    //注意number_entry的值是zip文件中的文件盒文件夹总数。与是否嵌套无关。
    //例如:
    //将3个文件打包成一个zip,那么获取到的该值就是3;
    //一个文件夹A,含有2个文件以及一个子文件夹B;B中含有1个文件。直接对A进行打包,那么调用该函数获取到的值是5。这是因为这个压缩包中,共含有2个文件//夹和3个文件,总数为5。
    typedef struct unz_global_info_s
    {
    	uLong number_entry;         // zip文件中的文件和文件夹总数
    	uLong size_comment;         // zip文件的注释所占大小
    } unz_global_info;
    

    返回值

    #define UNZ_OK                          (0)
    #define UNZ_END_OF_LIST_OF_FILE         (-100)
    #define UNZ_ERRNO                       (Z_ERRNO)
    #define UNZ_EOF                         (0)
    #define UNZ_PARAMERROR                  (-102)
    #define UNZ_BADZIPFILE                  (-103)
    #define UNZ_INTERNALERROR               (-104)
    #define UNZ_CRCERROR                    (-105)
    
    1. 对于zip文件中定位的当前文件,可以通过函数来获取其信息:
    int unzGetCurrentFileInfo(	unzFile file,
    							unz_file_info *pfile_info,
    							char *szFileName,
    							uLong fileNameBufferSize,
    							void *extraField,
    							uLong extraFieldBufferSize,
    							char *szComment,
    							uLong commentBufferSize);
    
    关于其参数:
    ①   unzFile file:已打开的unzFile对象
    
    ②   unz_file_info *pfile_info:一个头文件信息对象的指针,传入后,函数会将当前文件的信息填充到该指针指向的对象中。详见下面说明
    
    ③   char *szFileName:用于保存文件名,需在外部new出足够大的存储空间,函数会将文件的路径+文件名保存在该对象中。注意该文件名的路径是个相对路径,其最顶层为被压缩的最上层文件或文件夹
    
    ④   uLong fileNameBufferSize:与③统一,告知函数new了多大的char*内存
    
    ⑤   void* extraField:用于保存扩展内容,需在外部new出足够大的存储空间,函数会将文件的扩展内容保存在该对象中
    
    ⑥   uLong extraFieldBufferSize:与⑤统一,告知函数new了多大的内存
    
    ⑦   char* szComment:用于保存注释内容,需在外部new出足够大的存储空间,函数会将文件的注释内容保存在该对象中
    
    ⑧   uLong commentBufferSize:与⑦统一,告知函数new了多大的内存
    

    对于其中的unz_file_info结构体,定义如下:

    typedef struct unz_file_info_s
    {
    	uLong version;              // 压缩文件所使用的pkware版本	2 bytes
    	uLong version_needed;       // 解压文件所需pkware版本		2 bytes
    	uLong flag;                 // 全局方式位标记				2 bytes
    	uLong compression_method;   // 压缩方式					2 bytes
    	uLong dosDate;              // 文件最后修改日期时间			4 bytes
    	uLong crc;                  // CRC-32校验					4 bytes
    	uLong compressed_size;      // 压缩后大小					4 bytes
    	uLong uncompressed_size;    // 未压缩大小					4 bytes
    	uLong size_filename;        // 文件名长度					2 bytes
    	uLong size_file_extra;      // 文件扩展字段长度				2 bytes
    	uLong size_file_comment;    // 文件注释长度					2 bytes
     
    	uLong disk_num_start;       // 磁盘开始号					2 bytes
    	uLong internal_fa;          // 内部文件属性					2 bytes
    	uLong external_fa;          // 外部文件属性					4 bytes
     
    	tm_unz tmu_date;			   // 文件创建日期
    } unz_file_info;
    

    实际上,一般的zip文件很少使用扩展与注释。对于没有扩展与注释的,参数⑤⑦可以传入null,参数⑥⑧可以传入0。

    注意获取到的文件名。若该文件名以路径分隔符”/”结尾,表明这是个文件夹;否则表明这是个文件。

    判断一个文件名是文件还是文件夹,还可以利用external_fa字段。该字段的值会被填充为winnt.h中的FILE宏定义。通常,若external_fa  = 16,即0x00000010,则说明是个文件夹;若external_fa   = 32,即0x00000020,则说明是个文件。

    在winnt.h中:

    #define FILE_ATTRIBUTE_DIRECTORY            0x00000010  
    #define FILE_ATTRIBUTE_ARCHIVE              0x00000020 
    

    一般来说,在这里若external_fa !=FILE_ATTRIBUTE_DIRECTORY,则认为是个文件。

    对于已经定位到的zip中的单个文件,就可以执行解压缩了。解压缩过程如下:

    打开该定位到的文件:
    int unzOpenCurrentFile(unzFile file);
    返回值为执行的结果信息。
    
    对于加密的文件,需要传入密码:
    int unzOpenCurrentFilePassword(unzFile file, const char* password);
    
    若返回值不为UNZ_OK,则解压出错,可以根据返回值判断是文件本身问题还是解压问题。
    
    读取文件内容:
    int unzReadCurrentFile(unzFile file, voidp buf, unsigned len);
    
    传入unzFile对象,创建一个缓冲区用于存放读取的内容,将缓冲区指针和大小传入。
    
    由于缓冲区并不一定足够大,所以需要进行多次读取。每次读取,当前的读取位置都会被修改。
    
    例如,一个文件读取需要10M空间。创建了一个1M大小的缓冲区。第一次调用该函数读取,当前位置指向文件的开始,读了1M大小的数据,将该数据存入缓冲区中;第二继续调用该函数来读取,此时当前位置由于第一次的读取,已经指向了1M数据结尾的地方,所以第二次读取会从1M结尾开始,读取1M大小的数据……调用该函数10次,即可读取完所有的数据。
    
    文件的读取状况,是依靠返回值来判定的:
    
    return>0:正常读取了文件的一部分内容,返回值为读取的字节数
    
    return==0:没有数据被读取,说明文件已经读取完毕
    
    return<0:读取出错,返回错误码
    
    
    将缓冲区内容写入到创建的文件中:
    这需要借助操作系统的函数来进行。同样是要对一个文件进行多次写入。
    
    const int BUFFER_SIZE = 4096;
    char szReadBuffer[BUFFER_SIZE];
    while (TRUE)
    {
    	memset(szReadBuffer, 0, BUFFER_SIZE);	//清理缓冲区
    	int nReadFileSize = unzReadCurrentFile(unzfile, szReadBuffer, BUFFER_SIZE);	//读取
     
    	int result;
    	if (nReadFileSize > 0)	result = 1;	//读取文件部分数据
    	if (nReadFileSize == 0)	result = 0;	//读取文件结束
    	if (nReadFileSize < 0)	result = -1;	//读取文件失败
    	switch (result)
    	{
    	case 1:
    	{
    		//读取文件部分数据
    		//将其写入到创建的文件中
    	}
    	break;
    	case 0:
    	{
    		//读取文件结束
    		unzCloseCurrentFile(unzfile);
    		return;
    	}
    	break;
    	case -1:
    	{
    		//读取文件失败
    		unzCloseCurrentFile(unzfile);
    	}
    	break;
    	}
    
    }
    

    当前文件解析完毕,则跳转到下一个文件:

    int unzGoToNextFile(unzFile file);
    

    然后重复步骤上面的几个步骤

    若成功,则return UNZ_OK

    若失败,说明已到文件尾,则return UNZ_END_OF_LIST_OF_FILE

    对zip文件解压缩完毕后,要将文件关闭:

    int unzClose(unzFile file);
    

    对于zip中各个文件和文件夹的定位,可以使用以下函数:

    int unzGoToFirstFile(unzFile file);
    int unzGoToNextFile(unzFile file);
    int unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity);
    

    关于iCaseSensitivity参数:

    iCaseSensitivity = 1,则文件名的匹配区分大小写。

    iCaseSensitivity = 2,则文件名的匹配不区分大小写。

    iCaseSensitivity = 0,则文件名的匹配按操作系统自行决定。Unix使用1,Windows使用2

    对于zip中各个文件和文件夹的位置,可以使用索引:

    
    typedef struct unz_file_pos_s
    {
    	uLong pos_in_zip_directory;   // 文件在zip文件中的偏移
    	uLong num_of_file;            // 在文件中的索引
    } unz_file_pos;
     
    int unzGetFilePos(unzFile file, unz_file_pos* file_pos);
    int unzGoToFilePos(unzFile file, unz_file_pos* file_pos);
    

    unzGetFilePos函数会将当前定位文件的信息填入传入的unz_file_pos指针中。

    unzGoToFilePos函数会根据传入的unz_file_pos指针中的信息,将当前文件定位到指定文件。

    获取zip文件的注释:

    int unzGetGlobalComment(unzFile file, char *szComment, uLong uSizeBuf);
    
    
    留待后查,同时方便他人
    联系我:renhanlinbsl@163.com
  • 相关阅读:
    数据结构(2)-链表
    数据结构(1)-数组
    SpringMVC学习总结(一)--Hello World入门
    基本数据类型对象的包装类
    关于String的相关常见方法
    常见的集合容器应当避免的坑
    再一次生产 CPU 高负载排查实践
    分表后需要注意的二三事
    线程池没你想的那么简单(续)
    线程池没你想的那么简单
  • 原文地址:https://www.cnblogs.com/ives/p/14760562.html
Copyright © 2011-2022 走看看