zlib库可在git上自己clone下来然后使用cmake工具生成解决方案,编译、生成zlib二进制文件。然后将zlib库引入项目:
//zlib库支持
#include "../zlib/include/zlib.h"
#ifdef _DEBUG
#pragma comment(lib, "../zlib/lib/zlibd.lib")
#else
#pragma comment(lib, "../zlib/lib/zlib.lib")
#endif
定义一个文件结构
typedef struct tagZipperFileInfo
{
std::string m_strLocalPath;
std::string m_strRootPath;
std::string m_strFileName;
size_t m_FileSize;
}ZipperFileInfo;
压缩文件相关:
/*
* strFolder 需要被压缩的文件夹
* strOut 保存的文件
*/
void CompressFolder(std::string& strFolder, std::string& strOut)
{
//创建压缩的目标文件
std::ofstream dest(strOut, std::ios::binary | std::ios::trunc);
if (!dest.is_open()) {
//error
return;
}
dest.close();
std::vector<ZipperFileInfo> vecZipperFiles;
//遍历文件夹下的所有文件
OperateFolder(strFolder, strFolder, vecZipperFiles);
//压缩文件
gzFile gzOut = gzopen(strOut.c_str(), "wb");
CompressFiles(vecZipperFiles, gzOut);
gzclose(gzOut);
}
void OperateFolder(std::string& strFolder, std::string& strRoot, std::vector<ZipperFileInfo>& vecZipperFiles)
{
std::string searchPath = strFolder + "\\*";
WIN32_FIND_DATAA findData;
HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData);
if (hFind == INVALID_HANDLE_VALUE) {
//error
return;
}
do {
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (strcmp(findData.cFileName, ".") != 0 && strcmp(findData.cFileName, "..") != 0)
{
std::string subFolderPath = strFolder + "\\" + findData.cFileName;
OperateFolder(subFolderPath, strRoot, vecZipperFiles);
}
}
else {
std::string strLocalPath = strFolder + "\\" + findData.cFileName;
std::string strFileRootPath = strFolder;
std::string strFileName = findData.cFileName;
//需要根据strRoot分割出来需要压缩文件的相对路径名
std::string strTempPath;
size_t start = strFileRootPath.find(strRoot);
if (start == std::string::npos)
strTempPath = strFileRootPath; // 如果找不到根路径,则返回完整路径
else
{
if (strFileRootPath == strRoot)
strTempPath = strFileRootPath.substr(start + strRoot.length());
else
strTempPath = strFileRootPath.substr(start + strRoot.length() + 1);
}
ZipperFileInfo zipperFile;
zipperFile.m_strRootPath = strTempPath;
zipperFile.m_strLocalPath = strLocalPath;
zipperFile.m_strFileName = strFileName;
//计算文件大小
std::ifstream in(strLocalPath, std::ios::binary | std::ios::ate);
size_t fileSize = in.tellg();
in.seekg(0);
in.close();
zipperFile.m_FileSize = fileSize;
vecZipperFiles.push_back(zipperFile);
}
} while (FindNextFileA(hFind, &findData) != 0);
FindClose(hFind);
}
压缩文件:
void CompressFiles(std::vector<ZipperFileInfo>& vecZipperFiles, gzFile& gzOut)
{
//先往压缩文件中写入文件目录结构
std::vector<ZipperFileInfo> vecTemps;
for (int i = 0; i < vecZipperFiles.size(); i++)
{
ZipperFileInfo info = vecZipperFiles[i];
info.m_strLocalPath = "";
vecTemps.push_back(info);
}
int nFileCount = vecZipperFiles.size();
gzwrite(gzOut, reinterpret_cast<const void*>(&nFileCount), 4); //将压缩的文件数量写入压缩文件开头
//将压缩的文件信息写入压缩文件
gzwrite(gzOut, reinterpret_cast<const void*>(vecTemps.data()), vecTemps.size() * sizeof(ZipperFileInfo));
//再往压缩文件中写入需要压缩为文件内容
for (int i = 0; i < vecZipperFiles.size(); i++)
{
std::string strLocalPath = vecZipperFiles[i].m_strLocalPath;
std::ifstream infile(strLocalPath, std::ios::binary);
char buffer[4096];
while (infile)
{
infile.read(buffer, sizeof(buffer));
auto bytes = infile.gcount();
if (bytes > 0)
{
//写入目标压缩文件
gzwrite(gzOut, buffer, bytes);
}
}
infile.close();
}
}
文件解压相关:
//strFilePath 压缩文件路径
void DecompressFiles(std::string& strFilePath)
{
gzFile gzin = gzopen(strFilePath.c_str(), "rb");
if (!gzin) return; //open error
int nFileCount = 0;
gzread(gzin, &nFileCount, 4); //读取压缩的文件数量
// 读取文件列表信息
std::vector<ZipperFileInfo> vecZipperFiles;
ZipperFileInfo zipperFile;
for (int i = 0; i < nFileCount; i++)
{
if (gzread(gzin, &zipperFile, sizeof(ZipperFileInfo)) == sizeof(ZipperFileInfo))
vecZipperFiles.push_back(zipperFile);
}
std::string strAppPath = ""; //压缩文件输出目录
//先创建个输出目录
size_t szPos = strFilePath.find_last_of("\\");
if (szPos != std::string::npos)
{
std::string strTmp = strFilePath.substr(szPos + 1);
//分解出name
size_t szName = strTmp.find_last_of(".");
if (szName != std::string::npos)
{
std::string strName = strTmp.substr(0, szName);
strAppPath += strName;
}
}
CreateDirectoryA(strAppPath.c_str(), NULL);
//解压文件
for (int i = 0; i < vecZipperFiles.size(); i++)
{
ZipperFileInfo& info = vecZipperFiles[i];
std::string strRoot = info.m_strRootPath;
std::string strPath;
if (strRoot == "") //根目录下
strPath = strAppPath + "\\" + info.m_strFileName;
else
{
CreateFolder(strAppPath, strRoot);
strPath = strAppPath + "\\" + strRoot + "\\" + info.m_strFileName;
}
std::ofstream outFile(strPath, std::ios::binary);
if (!outFile) continue; //error
char buffer[1024];
size_t fileSize = info.m_FileSize;
while (fileSize > 0)
{
size_t bytesToRead = std::min(static_cast<size_t>(1024), fileSize);
int bytesRead = gzread(gzin, buffer, bytesToRead);
if (bytesRead <= 0) break; //read error
outFile.write(buffer, bytesRead);
fileSize -= bytesRead;
}
outFile.close();
}
gzclose(gzin);
}
递归生成压缩文件中的目录结构:
/*
* strRoot 解压缩的目标目录
* strDir 压缩文件的相对路径
*/
void CreateFolder(std::string& strRoot, std::string& strDir)
{
size_t szPos = strDir.find_first_of("\\");
if (szPos != std::string::npos)
{
std::string strName = strDir.substr(0, szPos);
std::string strPath = strRoot + "\\" + strName;
CreateDirectoryA(strPath.c_str(), NULL);
std::string strSubName = strDir.substr(szPos + 1);
std::string strTempRoot = strRoot + "\\" + strName;
CreateFolder(strTempRoot, strSubName);
}
else
{
std::string strPath = strRoot + "\\" + strDir;
CreateDirectoryA(strPath.c_str(), NULL);
}
}