本例用來簡單實現windows平臺下如何將一個目錄下的文件壓縮到指定的zip文件中,亦或是將一個zip文件的內容解壓縮到某個目錄。
以下是源碼,代碼中的註釋解釋了相關操作,一看就懂。
注:
本例將這兩個功能封裝在了一個叫ZipPack的命名空間中。
代碼中使用到的zip.h zip.cpp unzip.h unzip.cpp可以從www.info-zip.org下載。同時我也提供了具體的代碼示例:點擊下載
.h
#pragma once
#include <iostream>
namespace ZipPack
{
//* 遍歷文件夾下的所有文件到zip
//targetPath: 起始目錄
//currentDir: 當前遍歷所處的目錄
//hZip: HZIP 句柄地址
void BrowseFileToZip(std::wstring targetDir, std::wstring currentDir, void* hZip);
//* 將目錄打包爲zip
//targetPath: 要打包的目錄
//dstZip: 打包之後的zip文件位置
bool PackDirToZip(std::wstring targetDir, std::wstring dstZip);
//* 將zip文件解壓到對應的目錄
//targetZip:需要解壓的文件
//dstPath:解壓之後的文件所在目錄(如果目錄內已存在相同文件則會覆蓋)
bool UnPackZipToDir(std::wstring targetZip, std::wstring dstPath, std::string psw="");
};
.cpp
#include "ZipPack.h"
#include <windows.h>
#include <Shlwapi.h>
#include "zip.h"
#include "unzip.h"
#pragma comment(lib, "shlwapi.lib") //Windows API PathFileExists
bool ZipPack::PackDirToZip( std::wstring targetDir, std::wstring dstZip )
{
//用於輸出調試信息
std::wstring dbgInfo;
dbgInfo.resize(MAX_PATH);
if(targetDir.empty() || dstZip.empty())
{
wsprintfW(&dbgInfo[0], L"failed: empty path.");
OutputDebugStringW(dbgInfo.c_str());
return false;
}
//檢查目標路徑是否有效
BOOL bTargetPathExists = ::PathFileExistsW(targetDir.c_str());
if(!bTargetPathExists)
{
wsprintfW(&dbgInfo[0], L"failed: invalid path(%s).", targetDir.c_str());
OutputDebugStringW(dbgInfo.c_str());
return false;
}
//創建HZIP, 這裏默認不設置密碼,如有需要可傳入密碼參數
HZIP hZip = CreateZip(dstZip.c_str(), 0);
if(!IsZipHandleZ(hZip))
{
wsprintfW(&dbgInfo[0], L"failed: create zip file(%s) failed.", dstZip.c_str());
OutputDebugStringW(dbgInfo.c_str());
return false;
}
//* 將目錄下的所有子文件夾和子文件加入zip文件中
BrowseFileToZip(targetDir, targetDir, &hZip);
CloseZip(hZip);
return true;
}
void ZipPack::BrowseFileToZip(std::wstring targetDir, std::wstring currentDir, void* hZip)
{
HZIP* pHZip = (HZIP*)hZip;
//用於輸出調試信息
std::wstring dbgInfo;
dbgInfo.resize(MAX_PATH);
WIN32_FIND_DATA FindFileData;
HANDLE hListFile;
WCHAR szFilePath[MAX_PATH];
// 構造代表子目錄和文件夾路徑的字符串,使用通配符"*"
lstrcpy(szFilePath, currentDir.c_str());
// 註釋的代碼可以用於查找所有以“.txt”結尾的文件
// lstrcat(szFilePath, "\\*.txt");
lstrcat(szFilePath, L"\\*");
// 查找第一個文件/目錄,獲得查找句柄
hListFile = FindFirstFile(szFilePath, &FindFileData);
// 判斷句柄
if(hListFile == INVALID_HANDLE_VALUE)
{
wsprintfW(&dbgInfo[0], L"BrowseFileToZip Error:%d\n", GetLastError());
OutputDebugStringW(dbgInfo.c_str());
return ;
}
else
{
do
{
//如果不想顯示代表本級目錄和上級目錄的“.”和“..”,
//可以使用註釋部分的代碼過濾
if(lstrcmp(FindFileData.cFileName, TEXT(".")) == 0 ||
lstrcmp(FindFileData.cFileName, TEXT("..")) == 0)
{
continue;
}
// 打印文件名、目錄名
wsprintfW(&dbgInfo[0], L"%ws\t\t", FindFileData.cFileName);
OutputDebugStringW(dbgInfo.c_str());
// 判斷文件屬性,是否爲加密文件或者文件夾
if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)
{
wsprintfW(&dbgInfo[0], L"<加密> ");
OutputDebugStringW(dbgInfo.c_str());
}
// 判斷文件屬性,是否爲隱藏文件或文件夾
if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
{
wsprintfW(&dbgInfo[0], L"<隱藏> ");
OutputDebugStringW(dbgInfo.c_str());
}
// 判斷文件屬性,是否爲目錄
if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
wsprintfW(&dbgInfo[0], L"<DIR> ");
OutputDebugStringW(dbgInfo.c_str());
//子文件夾的絕對路徑
std::wstring absSubDir = currentDir;
absSubDir.append(L"\\");
absSubDir.append(FindFileData.cFileName);
//子文件夾的相對路徑
std::wstring tSubDir = absSubDir.substr(targetDir.length() + 1, absSubDir.length() - targetDir.length());
//將文件夾添加到ZIP文件
ZipAddFolder(*pHZip,tSubDir.c_str());
//遍歷子文件夾
BrowseFileToZip(targetDir, absSubDir, pHZip);
}
else //*不是目錄的當文件處理
{
//子文件的絕對路徑
std::wstring absSubDir = currentDir;
absSubDir.append(L"\\");
absSubDir.append(FindFileData.cFileName);
//子文件的相對路徑
std::wstring tSubDir = absSubDir.substr(targetDir.length() + 1, absSubDir.length() - targetDir.length());
ZipAdd(*pHZip,tSubDir.c_str(),absSubDir.c_str());
}
// 讀者可根據文件屬性表中的內容自行添加、判斷文件屬性
wsprintfW(&dbgInfo[0], L"\n");
OutputDebugStringW(dbgInfo.c_str());
}
while(FindNextFile(hListFile, &FindFileData));
}
}
bool ZipPack::UnPackZipToDir(std::wstring targetZip, std::wstring dstPath, std::string psw)
{
//用於輸出調試信息
std::wstring dbgInfo;
dbgInfo.resize(MAX_PATH);
if(!::PathFileExistsW(targetZip.c_str()) || !PathFileExistsW(dstPath.c_str()))
{
wsprintfW(&dbgInfo[0], L"UnPackZipToPath failed, invalid file or dir");
OutputDebugStringW(dbgInfo.c_str());
return false;
}
HZIP hz = OpenZip(&targetZip[0], psw.c_str());
if(hz == NULL)
{
wsprintfW(&dbgInfo[0], L"UnPackZipToPath failed, open zip(%s) failed", targetZip.c_str());
OutputDebugStringW(dbgInfo.c_str());
return false;
}
bool bRtn;
bRtn = true;
ZRESULT zRtn;
zRtn = SetUnzipBaseDir(hz, dstPath.c_str());
if(zRtn == ZR_OK)
{
ZIPENTRY ze;
zRtn = GetZipItem(hz,-1,&ze);
if(zRtn == ZR_OK)
{
int numitems = ze.index;
for(int zi=0; zi<numitems; zi++)
{
ZIPENTRY zetmp;
zRtn = GetZipItem(hz, zi, &zetmp);
if(zRtn != ZR_OK)
{
bRtn = false;
}
zRtn = UnzipItem(hz, zi, zetmp.name);
if(zRtn != ZR_OK)
{
//如果外邊是隻讀文件,那麼就不處理
//bRtn = false;
switch(zRtn)
{
case ZR_NOFILE:
case ZR_NODUPH:
case ZR_NOALLOC:
case ZR_WRITE:
break;
default:
bRtn = false;
break;
}
}
}
}
else
{
bRtn = false;
}
}
else
{
bRtn = false;
}
CloseZip(hz);
wsprintfW(&dbgInfo[0], L"UnPackZipToPath, success(%d)", bRtn);
OutputDebugStringW(dbgInfo.c_str());
return bRtn;
}
使用示例:
#include "ZipPack.h"
int main(int argc, char** argv)
{
ZipPack::PackDirToZip(L"F:\\WorkSpace2.0\\VSProject\\WindowsProject1",L"F:\\WorkSpace2.0\\VSProject\\ZipPack\\test.zip");
ZipPack::UnPackZipToDir(L"F:\\WorkSpace2.0\\VSProject\\ZipPack\\test.zip", L"F:\\WorkSpace2.0\\VSProject\\ZipPack\\UNPACK");
return 0;
}
運行之後就能看到打包的zip文件也解壓之後的文件了。