需要注意Release和Debug使用的dll可能有差异,Release时需要使用对应的Dll
zlib源码文件中zlib123\contrib\vstudio此文件夹包含所需的zip、unzip相关实例代码minizip
最新版为zlib1.2.11
- 相关库文件
- 导入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重复定义
1. 在zlib源码的zlibvc工程属性-预处理器定义里面去掉 ASMINF、ASMV 定义,屏蔽掉汇编模块
2. 打开zlib-1.2.11\contrib\masmx86下面的汇编文件inffas32.asm,将里面_inflate_fast全部替换成其他任意函数名
zip相关实现
zip解压缩
- 将zlib-1.x.x\contrib\minizip文件夹下除miniunz.c和minizip.c以外的.h与.c文件放到项目目录下,并将zip.h与unzip.h导入到工程中。
- 打开需要解压缩的文件
//传入zip文件的绝对路径,返回一个unzFile对象。这是一个void*指针,用于指向打开的zip文件
unzFile unzOpen(const char *path);
操作完毕后需要关闭已打开的压缩文件:
int unzClose OF(unzFile file);
- 获取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)
- 对于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);
封装后的代码
UZip