最近因為項目的需要,要對zip壓縮文件進行批量解壓。在網上查閱了相關的資料后,最終使用zlib開源庫實現了該功能。本文將對zlib開源庫進行簡單介紹,并給出一個使用zlib開源庫對zip壓縮文件進行解壓的示例程序。
1.zlib開源庫
zlib是應用最廣泛的壓縮與解壓縮zip文件的免費開源庫,提供了數據壓縮與解壓縮的函式庫。
zlib中最關鍵的函數有以下兩個:
(1)int compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
(2)int uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
其中,函數compress()用于將源緩沖區數據壓縮到目的緩沖區,函數uncompress()用于將源緩沖區數據解壓到目的緩沖區。
由此可見,zlib只是一個針對gzip以及deflate算法的庫,用于將一段內存壓縮/解壓之后放到另一段內存上,這離壓縮/解壓文件甚至文件夾的目標還很遠。但是,它提供了一個叫做minizip的例子給出了操作zip文件的方法。
2.minizip簡介
minizip是zlib的上層庫,它封裝了與zip文件相關的操作。
minizip中與解壓縮相關的API有以下幾個:
(1)unzFile unzOpen(const char *path);
(2)int unzClose(unzFile file);
(3)int unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info);
(4)int unzGoToNextFile(unzFile file);
(5)int unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize,
void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize);
(6)int unzOpenCurrentFile(unzFile file);
(7)int unzCloseCurrentFile(unzFile file);
(8)int unzReadCurrentFile(unzFile file, voidp buf, unsigned len);
有了以上這些API,我們就可以對zip文件進行解壓縮了。一個完整的解壓過程應該包含以下這些步驟:
(1)調用unzOpen()函數打開一個zip壓縮文件,其參數是zip壓縮文件的路徑。
(2)調用unzGetGlobalInfo()函數來獲取zip壓縮文件的一些信息(如內部文件個數等),這些信息會保存在傳入參數pglobal_info中。
(3)然后開始遍歷zip文件中的內部文件,初始時會自動定位到第一個內部文件,處理完一個內部文件后可以使用unzGoToNextFile()函數來跳轉到下一個內部文件。
(4)對于每個內部文件來說,可以先調用unzGetCurrentFileInfo()函數來獲取該內部文件信息(如文件的路徑、文件大小等),這些信息會保存在傳入參數pfile_info中。
(5)調用unzOpenCurrentFile()函數打開該內部文件。
(6)調用unzReadCurrentFile()函數讀取該內部文件內容。
(7)該內部文件讀取完畢之后,調用unzCloseCurrentFile()函數對內部文件進行關閉。
(8)zip文件中的所有內部文件遍歷完成之后,調用unzClose()函數關閉打開的zip壓縮文件。
3.示例程序
了解了以上的內容之后,我們就可以編寫程序使用zlib以及minizip對zip壓縮文件進行解壓縮了。
3.1加載相關的頭文件及庫文件
在使用zlib以及minizip之前,我們需要加載相關的頭文件及庫文件到工程中。需要加載的頭文件有zlib.h、unzip.h、zip.h。需要加載的庫文件有zlib.lib、minizip.lib。需要添加的動態鏈接庫zlib1.dll。這些文件都可以從網上下載得到。
1 #include "zlib/zlib.h" 2 #include "zlib/unzip.h" 3 #include "zlib/zip.h" 4 #pragma comment(lib, "zlib.lib") 5 #pragma comment(lib, "minizip.lib")
3.2配置工程
因為zlib以及minizip是用C語言編寫的,在VC6.0中使用時,需要對工程進行如下配置,否則會出現編譯鏈接通不過的問題。
(1)在“工程”、“設置”中選擇“連接”標簽頁,在“分類”中選擇輸入,在“忽略庫”中加入MSVCRT。
(2)在“工程”、“設置”中選擇“C/C++”標簽頁,在“分類”中選擇Code Generation,在“Use run-time library”中選擇“Debug Multithreaded DLL”。
(3)在“工程”、“設置”中選擇“C/C++”標簽頁,在“分類”中選擇常規,在“預處理程序定義”中加入_AFXDLL。
3.3示例程序
如下的示例程序演示了如何調用minizip中的API對zip文件進行解壓。
1 /* 2 * 函數功能 : 解壓zip文件 3 * 備 注 : 參數strFilePath表示zip壓縮文件的路徑 4 * 參數strTempPath表示要解壓到的文件目錄 5 * 作 者 : 博客園 依舊淡然(http://www.cnblogs.com/menlsh/) 6 */ 7 void CZlibDemoDlg::UnzipFile(CString strFilePath, CString strTempPath) 8 { 9 int nReturnValue; 10 11 //打開zip文件 12 unzFile unzfile = unzOpen(strFilePath); 13 if(unzfile == NULL) 14 { 15 MessageBox("打開zip文件失敗!", "提示", MB_OK|MB_ICONWARNING); 16 return; 17 } 18 19 //獲取zip文件的信息 20 unz_global_info* pGlobalInfo = new unz_global_info; 21 nReturnValue = unzGetGlobalInfo(unzfile, pGlobalInfo); 22 if(nReturnValue != UNZ_OK) 23 { 24 MessageBox("獲取zip文件信息失敗!", "提示", MB_OK|MB_ICONWARNING); 25 return; 26 } 27 28 //解析zip文件 29 unz_file_info* pFileInfo = new unz_file_info; 30 char szZipFName[MAX_PATH]; //存放從zip中解析出來的內部文件名 31 for(int i=0; i<pGlobalInfo->number_entry; i++) 32 { 33 //解析得到zip中的文件信息 34 nReturnValue = unzGetCurrentFileInfo(unzfile, pFileInfo, szZipFName, MAX_PATH, 35 NULL, 0, NULL, 0); 36 if(nReturnValue != UNZ_OK) 37 { 38 MessageBox("解析zip文件信息失敗!", "提示", MB_OK|MB_ICONWARNING); 39 return; 40 } 41 42 //判斷是文件夾還是文件 43 switch(pFileInfo->external_fa) 44 { 45 case FILE_ATTRIBUTE_DIRECTORY: //文件夾 46 { 47 CString strDiskPath = strTempPath + _T("//") + szZipFName; 48 CreateDirectory(strDiskPath, NULL); 49 } 50 break; 51 default: //文件 52 { 53 //創建文件 54 CString strDiskFile = strTempPath + _T("//") + szZipFName; 55 HANDLE hFile = CreateFile(strDiskFile, GENERIC_WRITE, 56 0, NULL, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL); 57 if(hFile == INVALID_HANDLE_VALUE) 58 { 59 MessageBox("創建文件失敗!", "提示", MB_OK|MB_ICONWARNING); 60 return; 61 } 62 63 //打開文件 64 nReturnValue = unzOpenCurrentFile(unzfile); 65 if(nReturnValue != UNZ_OK) 66 { 67 MessageBox("打開文件失敗!", "提示", MB_OK|MB_ICONWARNING); 68 CloseHandle(hFile); 69 return; 70 } 71 72 //讀取文件 73 const int BUFFER_SIZE = 4096; 74 char szReadBuffer[BUFFER_SIZE]; 75 while(TRUE) 76 { 77 memset(szReadBuffer, 0, BUFFER_SIZE); 78 int nReadFileSize = unzReadCurrentFile(unzfile, szReadBuffer, BUFFER_SIZE); 79 if(nReadFileSize < 0) //讀取文件失敗 80 { 81 MessageBox("讀取文件失敗!", "提示", MB_OK|MB_ICONWARNING); 82 unzCloseCurrentFile(unzfile); 83 CloseHandle(hFile); 84 return; 85 } 86 else if(nReadFileSize == 0) //讀取文件完畢 87 { 88 unzCloseCurrentFile(unzfile); 89 CloseHandle(hFile); 90 break; 91 } 92 else //寫入讀取的內容 93 { 94 DWORD dWrite = 0; 95 BOOL bWriteSuccessed = WriteFile(hFile, szReadBuffer, BUFFER_SIZE, &dWrite, NULL); 96 if(!bWriteSuccessed) 97 { 98 MessageBox("讀取文件失敗!", "提示", MB_OK|MB_ICONWARNING); 99 unzCloseCurrentFile(unzfile); 100 CloseHandle(hFile); 101 return; 102 } 103 } 104 } 105 } 106 break; 107 } 108 unzGoToNextFile(unzfile); 109 } 110 111 //關閉 112 if(unzfile) 113 { 114 unzClose(unzfile); 115 } 116 }
3.4運行結果
調用上述的UnzipFile()方法對某個zip文件進行解壓,如圖1所示。
圖1 解壓zip文件
解壓后,可以看到文件夾123中的內容如圖2所示。
圖2 解壓后的文件
文章列表