最近碰到了这么个需求:为了节省流量,在传输的时候需要使用zip文件传输,下载完成之后,在客户端解压zip文件。
解决方法:由于需要跨平台,在iOS和Android都使用,所以经过考虑决定使用zlib库来解压zip文件。
zlib github 地址 , 下载完成之后,在解压的文件中拷贝 zlib.h , zconf.h 两个头文件,在contrib --> minizip 文件夹中,拷贝其中的 unzip.h , ioapi.h , unzip.c , ioapi.c 文件,到你的工程中去, 然后include一下zlib.h 文件即可。
当前使用的zlib版本是 **1.2.8 **
zlib库使用步骤如下:
- 打开zip文件
- 获取zip文件信息
- 循环遍历文件,如果遇到文件夹则创建文件夹,如果遇到文件则把数据写入文件中
- 解压zip文件核心代码如下: 需要传入一个zip文件的路径,和需要解压到的路径
int BPDecompress::BPDecompressZip(string zipFilePath, string strFolder)
{
// 1. open zip
unzFile zipfile = unzOpen(zipFilePath.c_str());
if (zipfile == NULL)
{
CP_LOGE("open zip failed , path = %s",zipFilePath.c_str());
return -1;
}
// 2. get global info
unz_global_info global_info;
if (unzGetGlobalInfo(zipfile, &global_info)!=UNZ_OK){
unzClose(zipfile);
CP_LOGE("get global info failed\n");
return -1;
}
// 3. loop files
for (uLong i = 0; i<global_info.number_entry; ++i){
unz_file_info64 file_info64;
char filename[1024]={0};
unzGetCurrentFileInfo64(zipfile, &file_info64, filename, sizeof(filename), NULL, 0, NULL, 0);
const size_t filename_length = strlen(filename);
char name[1024] = {0};
if (filename[filename_length-1] == '/')
{// make folder
sprintf(name, "%s/%s", strFolder.c_str(), filename);
BPCreateDir(name);
}else{
if (unzOpenCurrentFile(zipfile) != UNZ_OK)
{
unzClose(zipfile);
CP_LOGE("open current file failed\n");
return -1;
}
sprintf(name, "%s/%s", strFolder.c_str(), filename);
if (BPWriteData(zipfile, name) < 0) {
unzCloseCurrentFile(zipfile);
unzClose(zipfile);
CP_LOGE("wtite data into file failed\n");
return -1;
}
// to set file time
}
unzCloseCurrentFile(zipfile);
if ((i+1) < global_info.number_entry && unzGoToNextFile(zipfile) != UNZ_OK) {
unzClose(zipfile);
CP_LOGE("go to next failed\n");
return -1;
}
}
unzClose(zipfile);
return 0;
}
其中:
CP_LOGE 为宏定义 ,可以加入自己定义的打印信息的宏
BPCreateDir 为创建文件夹的方法 , 用c语言实现即可
BPWriteData 为数据写入到文件中的方法
- 写入数据到文件中的核心代码如下:需要传入一个unzFile 和 写入的路径
int BPDecompress::BPWriteData(unzFile &zipfile, const char *destPathName)
{
if (destPathName == NULL) {
CP_LOGE("name is null\n");
return -1;
}
if ( BPCreateDir(destPathName) != 0)
{
CP_LOGE("[BPWriteData] create dir failed . path = %s\n",destPathName);
return -1;
}
// 删除以.开头的文件
string s_path = destPathName;
int index = (int)s_path.find_last_of("/");
string name = s_path.substr(index+1);
if (name.find(".") == 0) return 0;
FILE *fp = fopen(destPathName, "wb");
if (fp == NULL) {
CP_LOGE("open file failed. destPathName = %s\n",destPathName);
return -1;
}
char read_buffer[1024] = {0};
int error = UNZ_OK;
do {
error = unzReadCurrentFile(zipfile, read_buffer, 1024);
if (error < 0 )
{
CP_LOGE("[unzReadCurrentFile] error = %d\n", error);
return -1;
}
if (error > 0) {
fwrite(read_buffer, error, 1, fp);
}
} while (error > 0);
fclose(fp);
fp = NULL;
return 0;
}