libz用的比较多,在libz中有个minizip,实现了对压缩和解压缩的封装,
这里使用该文件封装为C++类,实现对整个压缩包的解压;
使用代码如下:main.cpp
//gcc zipHelper.cpp main.cpp ./minizip/ioapi.c ./minizip/zip.c ./minizip/unzip.c -o testzip -lz -lstdc++
#include <iostream>
#include "zipHelper.h"
using namespace std;
int main(int argc, char** argv) {
cPackFile packTool;
cUnpackFile unpackTool;
//packTool.CreateZipFromDir("/robin1/testZip/test", "/robin1/testZip/example.zip");
unpackTool.CreateDirFromZip("/robin1/testZip/test1", "/robin1/testZip/example.zip");
return 0;
}
调用的类文件:zipHelper.h
#pragma once
#ifndef ZIP_H
#define ZIP_H
#include <iostream>
#include <fstream>
#include <string>
#include "minizip/zip.h"
#include "minizip/unzip.h"
using namespace std;
class cPackFile
{
public:
//将某个目录或者文件(dirName)压缩为zipFileName(.zip)文件
int CreateZipFromDir(const string &dirName, const string & zipFileName);
cPackFile();
~cPackFile();
private:
int count = 0;
//递归添加子目录到zip文件
void CollectFilesInDirToZip(zipFile zf, const string & strPath, const string & parentDir);
void AddFileToZip(zipFile zf, const string & fileNameInZip, const string & srcFile);
};
static inline bool IsFileExist(const string &pPath);
class cUnpackFile
{
private:
bool splitDirAndName(const string &str, string& dir);
public:
cUnpackFile();
~cUnpackFile();
void CreateDirFromZip(const string & dirName, const string &zipFileName);//解压到文件夹dirName
void CreateFileFromZip(const string & fName, const string & zipFileName);//解压第一个文件到文件fName
};
#endif
源文件为:zipHelper.cpp
#include "zipHelper.h"
#include <stdio.h>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include "PathUtil.h"
using namespace std;
using namespace oneapm;
//将文件添加到zip文件中,注意如果源文件srcFile为空则添加空目录
// fileNameInZip: 在zip文件中的文件名,包含相对路径
void cPackFile::AddFileToZip(zipFile zf, const string &fileNameInZip, const string &srcFile)
{
FILE *srcfp = NULL;
//初始化写入zip的文件信息
// zip_fileinfo zi;
zip_fileinfo zi = {0};
zi.tmz_date.tm_sec = 0;
zi.tmz_date.tm_min = 0;
zi.tmz_date.tm_hour = 0;
zi.tmz_date.tm_mday = 0;
zi.tmz_date.tm_mon = 0;
zi.tmz_date.tm_year = 0;
zi.dosDate = 0;
zi.internal_fa = 0;
zi.external_fa = 0;
//如果srcFile为空,加入空目录
string new_file_name = fileNameInZip;
if (srcFile == "")
{
new_file_name += "/";
}
//在zip文件中创建新文件
zipOpenNewFileInZip(zf, new_file_name.c_str(), &zi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
if (srcFile != "") // is a real file, or will be a dir name
{
//打开源文件
srcfp = fopen(srcFile.c_str(), "rb");
if (srcfp == NULL)
{
printf("无法添加文件: %s !\n", srcFile);
zipCloseFileInZip(zf); //关闭zip文件
return;
}
//读入源文件并写入zip文件
char buf[100 * 1024]; // buffer
int numBytes = 0;
while (!feof(srcfp))
{
numBytes = fread(buf, 1, sizeof(buf), srcfp);
zipWriteInFileInZip(zf, buf, numBytes);
if (ferror(srcfp))
break;
}
//关闭源文件
fclose(srcfp);
}
count++;
//关闭zip文件
zipCloseFileInZip(zf);
}
//递归添加子目录到zip文件
// zip, real path in fs, basedir name in zip
void cPackFile::CollectFilesInDirToZip(zipFile zf, const string & strPath, const string & parentDir)
{
if (false == PathUtil::isDirectory(strPath))
{
return;
}
DIR * p_dir = opendir(strPath.c_str());
if (p_dir == NULL)
{
std::cout << "Opendir error: " << strerror(errno) << std::endl;
return ;
}
string currentPath;
string zipPath;
int result = 0;
struct dirent *p_dirent;
while ((p_dirent = readdir(p_dir)) != NULL)
{
currentPath = strPath + "/" + p_dirent->d_name; // fs name path
zipPath = parentDir + "/" + p_dirent->d_name; // path in zip
if (PathUtil::isDirectory(currentPath) && (0 != strcmp(p_dirent->d_name, ".")) && (0 != strcmp(p_dirent->d_name, "..")))
{
AddFileToZip(zf, zipPath, ""); //在zip文件中生成目录结构
CollectFilesInDirToZip(zf, currentPath, zipPath); //递归收集子目录文件
}
else if ((0 != strcmp(p_dirent->d_name, ".")) && (0 != strcmp(p_dirent->d_name, "..")))
{
AddFileToZip(zf, zipPath, currentPath); //将文件添加到zip文件中
}
}
closedir(p_dir);
}
//将某个目录或者文件(dirName)压缩为zipFileName(.zip)文件
int cPackFile::CreateZipFromDir(const string &dirName, const string &zipFileName)
{
struct stat buffer;
int ret = stat(dirName.c_str(), &buffer);
if (ret != 0)
return -1;
zipFile newZipFile = zipOpen(zipFileName.c_str(), APPEND_STATUS_CREATE); //创建zip文件
if (newZipFile == NULL)
{
printf("无法创建zip文件!\n");
return -2;
}
// from /robin1/test/dir to ====> dir
string tempName = "";
auto pos = dirName.find_last_of("\/");
if (dirName.npos == pos)
{
tempName = dirName;
}
else
{
tempName = dirName.substr(pos + 1);
}
// only one file
if (S_ISREG(buffer.st_mode))
{
AddFileToZip(newZipFile, tempName, dirName);
}
if (S_ISDIR(buffer.st_mode)) // is a directory
{
AddFileToZip(newZipFile, tempName, "");
CollectFilesInDirToZip(newZipFile, dirName, tempName);
}
zipClose(newZipFile, NULL); //关闭zip文件
return count;
}
cPackFile::cPackFile()
{
}
cPackFile::~cPackFile()
{
}
/
// test normal file
static inline bool IsFileExist(const string &pPath)
{
struct stat buffer;
int ret = stat(pPath.c_str(), &buffer);
if (ret != 0)
return false;
// if (ENOENT == errno)
// return false;
if (S_ISREG(buffer.st_mode))
return true;
return false;
}
// trim the last filename
// true: dir/
// false: dir/subdir dir/file file
bool cUnpackFile::splitDirAndName(const string &str, string& dir)
{
unsigned pos = str.find_last_of('/');
if (pos != std::string::npos)
{
dir = str.substr(0, pos);
if (pos == str.length() -1)
return true;
return false;
}
pos = str.find_last_of('\\');
if (pos != std::string::npos)
{
dir = str.substr(0, pos);
if (pos == str.length() -1)
return true;
return false;
}
return false;
}
bool writeToFile(const string & filepath, unzFile unZipDir)
{
FILE *pFile = fopen(filepath.c_str(), "wb");
if (!pFile)
{
printf("无法打开输出文件 %s \n", filepath);
return false;
}
int nReadBytes = 0;
char buffer[4096 * 10];
do
{
nReadBytes = unzReadCurrentFile(unZipDir, buffer, 4096 * 10);
if (nReadBytes > 0)
fwrite(buffer, nReadBytes, 1, pFile);
}while (nReadBytes > 0);
fclose(pFile);
return true;
}
void cUnpackFile::CreateDirFromZip(const string & dirName, const string & zipFileName)
{
bool slashFlag = true;
unzFile unZipDir = unzOpen(zipFileName.c_str());
// remove last '/'
string dirBase = dirName;
if (dirBase.length() > 0 && dirBase.at(dirBase.length() -1) == '/')
dirBase = dirName.substr(0, dirName.length() -1);
if (PathUtil::isFile(dirName))
{
printf("path is a file, 无法解压zip文件!");
return;
}
if (0 != PathUtil::createDir(dirName))
{
printf("cant't create dir %s \n", dirName.c_str());
return;
}
int nResult = unzGoToFirstFile(unZipDir);
char szCurrentFile[260];
unz_file_info unZipFileInfo;
while (nResult == UNZ_OK)
{
unzGetCurrentFileInfo(unZipDir, &unZipFileInfo, szCurrentFile, sizeof(szCurrentFile), NULL, 0, NULL, 0);
std::string filePath = std::string(szCurrentFile);
std::string dirPart = "";
std::string dirCurrent = "";
bool bDir = this->splitDirAndName(szCurrentFile, dirPart);
// path have dirs
if (dirPart.length() > 0)
{
dirCurrent = dirBase + "/" + dirPart;
int ret = PathUtil::createDir(dirCurrent);
if(ret != 0)
{
break;
}
if (true == bDir)
{
nResult = unzGoToNextFile(unZipDir);
continue; //文件夹项
}
}
//int size = unZipFileInfo.uncompressed_size;
if (UNZ_OK == unzOpenCurrentFilePassword(unZipDir, NULL))
{
string filePos = dirBase + "/" + filePath;
writeToFile(filePos, unZipDir);
unzCloseCurrentFile(unZipDir);
}
nResult = unzGoToNextFile(unZipDir);
}
unzClose(unZipDir);
}
void cUnpackFile::CreateFileFromZip(const string &fName, const string & zipFileName)
{
bool slashFlag = true;
unzFile unZipDir = unzOpen(zipFileName.c_str());
if (unZipDir == NULL)
{
printf("无法解压zip文件!");
return;
}
int nResult = unzGoToFirstFile(unZipDir);
char szCurrentFile[260];
unz_file_info unZipFileInfo;
if (nResult == UNZ_OK)
{
unzGetCurrentFileInfo(unZipDir, &unZipFileInfo, szCurrentFile, sizeof(szCurrentFile), NULL, 0, NULL, 0);
//int size = unZipFileInfo.uncompressed_size;
if (UNZ_OK == unzOpenCurrentFilePassword(unZipDir, NULL))
{
writeToFile(fName, unZipDir);
unzCloseCurrentFile(unZipDir);
}
}
unzClose(unZipDir);
}
cUnpackFile::cUnpackFile()
{
}
cUnpackFile::~cUnpackFile()
{
}
使用的时候,需要将minizip拷贝到当前目录,编译即可;
参考的文档:http://t.csdn.cn/aCfC6
该帖子实现了windows版本的功能;