C++ 解压文件及文件夹 使用zlib开源库
使用zlib-1.2.11版本的开源库,实现我需要的对文件或者文件夹的解压,查阅了一些博客大牛的资料,后面根据自己的需要修改。这是续上一篇的压缩,好久了都忘记这回事了。下面给出我的代码:
#include "stdafx.h"
#include <string>
#include <iostream>
#include <vector>
#include <Shlwapi.h>
#include "zip.h"
#include "unzip.h"
#include "zlib.h"
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <sstream>
using namespace std;
#pragma comment(lib, "Shlwapi.lib")
//主要的解压函数
void UnzipFile(const std::string& strFilePath, const std::string& strTempPath);
//额外处理函数
std::string& replace_all(std::string& str, const std::string& old_value, const std::string& new_value);
BOOL CreatedMultipleDirectory(const std::string& direct);
int _tmain(int argc, _TCHAR* argv[])
{
std::string srcFilePath = "C:\\TDDownload\\mysql\\mysql-5.5.19-win32.zip";
std::string tempdir = "D:\\Mytest\\server\\temp";
if (!::PathFileExistsA(tempdir.c_str()))
{
CreatedMultipleDirectory(tempdir);
}
UnzipFile(srcFilePath , tempdir);
system("pause");
return 0;
}
void UnzipFile(const std::string& strFilePath, const std::string& strTempPath)
{
int nReturnValue;
string tempFilePath;
string srcFilePath(strFilePath);
string destFilePath;
std::cout << "Start unpacking the package... " << endl;
//打开zip文件
unzFile unzfile = unzOpen(srcFilePath.c_str());
if (unzfile == NULL)
{
return;
}
//获取zip文件的信息
unz_global_info* pGlobalInfo = new unz_global_info;
nReturnValue = unzGetGlobalInfo(unzfile, pGlobalInfo);
if (nReturnValue != UNZ_OK)
{
std::cout << "The number of compressed package files is " << pGlobalInfo->number_entry << endl;
return;
}
//解析zip文件
unz_file_info* pFileInfo = new unz_file_info;
char szZipFName[MAX_PATH] = { 0 };
char szExtraName[MAX_PATH] = { 0 };
char szCommName[MAX_PATH] = { 0 };
//存放从zip中解析出来的内部文件名
for (int i = 0; i < pGlobalInfo->number_entry; i++)
{
//解析得到zip中的文件信息
nReturnValue = unzGetCurrentFileInfo(unzfile, pFileInfo, szZipFName, MAX_PATH, szExtraName, MAX_PATH, szCommName, MAX_PATH);
if (nReturnValue != UNZ_OK)
return;
std::cout << "ZipName: " << szZipFName << "Extra: " << szExtraName << "Comm: " << szCommName << endl;
string strZipFName = szZipFName;
if (pFileInfo->external_fa == FILE_ATTRIBUTE_DIRECTORY || (strZipFName.rfind('/') == strZipFName.length() - 1))
{
destFilePath = strTempPath + "//" + szZipFName;
CreateDirectoryA(destFilePath.c_str(), NULL);
}
else
{
//创建文件
string strFullFilePath;
tempFilePath = strTempPath + "/" + szZipFName;
strFullFilePath = tempFilePath;//保存完整路径
int nPos = tempFilePath.rfind("/");
int nPosRev = tempFilePath.rfind("\\");
if (nPosRev == string::npos && nPos == string::npos)
continue;
size_t nSplitPos = nPos > nPosRev ? nPos : nPosRev;
destFilePath = tempFilePath.substr(0, nSplitPos + 1);
if (!PathIsDirectoryA(destFilePath.c_str()))
{
//将路径格式统一
destFilePath = replace_all(destFilePath, "/", "\\");
//创建多级目录
int bRet = CreatedMultipleDirectory(destFilePath);
}
strFullFilePath = replace_all(strFullFilePath, "/", "\\");
HANDLE hFile = CreateFileA(strFullFilePath.c_str(), GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return;
}
//打开文件
nReturnValue = unzOpenCurrentFile(unzfile);
if (nReturnValue != UNZ_OK)
{
CloseHandle(hFile);
return;
}
//读取文件
uLong BUFFER_SIZE = pFileInfo->uncompressed_size;;
void* szReadBuffer = NULL;
szReadBuffer = (char*)malloc(BUFFER_SIZE);
if (NULL == szReadBuffer)
{
break;
}
while (TRUE)
{
memset(szReadBuffer, 0, BUFFER_SIZE);
int nReadFileSize = 0;
nReadFileSize = unzReadCurrentFile(unzfile, szReadBuffer, BUFFER_SIZE);
if (nReadFileSize < 0) //读取文件失败
{
unzCloseCurrentFile(unzfile);
CloseHandle(hFile);
return;
}
else if (nReadFileSize == 0) //读取文件完毕
{
unzCloseCurrentFile(unzfile);
CloseHandle(hFile);
break;
}
else //写入读取的内容
{
DWORD dWrite = 0;
BOOL bWriteSuccessed = WriteFile(hFile, szReadBuffer, BUFFER_SIZE, &dWrite, NULL);
if (!bWriteSuccessed)
{
unzCloseCurrentFile(unzfile);
CloseHandle(hFile);
return;
}
}
}
free(szReadBuffer);
}
unzGoToNextFile(unzfile);
}
delete pFileInfo;
delete pGlobalInfo;
//关闭
if (unzfile)
{
unzClose(unzfile);
}
std::cout << "End unpacking the package... " << endl;
}
std::string& replace_all(std::string& str, const std::string& old_value, const std::string& new_value)
{
while (true)
{
std::string::size_type pos(0);
if ((pos = str.find(old_value)) != std::string::npos)
str.replace(pos, old_value.length(), new_value);
else
break;
}
return str;
}
BOOL CreatedMultipleDirectory(const std::string& direct)
{
std::string Directoryname = direct;
if (Directoryname[Directoryname.length() - 1] != '\\')
{
Directoryname.append(1, '\\');
}
std::vector< std::string> vpath;
std::string strtemp;
BOOL bSuccess = FALSE;
for (int i = 0; i < Directoryname.length(); i++)
{
if (Directoryname[i] != '\\')
{
strtemp.append(1, Directoryname[i]);
}
else
{
vpath.push_back(strtemp);
strtemp.append(1, '\\');
}
}
std::vector< std::string>::iterator vIter = vpath.begin();
for (; vIter != vpath.end(); vIter++)
{
bSuccess = CreateDirectoryA(vIter->c_str(), NULL) ? TRUE : FALSE;
}
return bSuccess;
}
zlib库自行下载来编译,然后加入到自己的项目里面去,(需要重新编译哦,不顺利的话可能会遇到很多问题哦x_O)。在下刚出自茅庐,不足之处还望指教,相互学习。基本上对文件的压缩解压,这两篇文章已经能够满足了,但是对于压缩解压的实时进度,那就需要自己实现该。似乎zlib没有提供回调进度(不知道是我还没发现还是真实没有?)。进度这一块虽然已经实现了,但是对单个文件的进度处理还有些问题。zlib也支持.rar的压缩解压,之前试过,具体不大记得了。后续再上传demo吧!