最近由於項目的須要,要對zip壓縮文件進行批量解壓。在網上查閱了相關的資料後,最終使用zlib開源庫實現了該功能。本文將對zlib開源庫進行簡單介紹,並給出一個使用zlib開源庫對zip壓縮文件進行解壓的示例程序。算法
1.zlib開源庫函數
zlib是應用最普遍的壓縮與解壓縮zip文件的免費開源庫,提供了數據壓縮與解壓縮的函式庫。spa
zlib中最關鍵的函數有如下兩個:code
(1)int compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);blog
(2)int uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);ip
其中,函數compress()用於將源緩衝區數據壓縮到目的緩衝區,函數uncompress()用於將源緩衝區數據解壓到目的緩衝區。內存
因而可知,zlib只是一個針對gzip以及deflate算法的庫,用於將一段內存壓縮/解壓以後放到另外一段內存上,這離壓縮/解壓文件甚至文件夾的目標還很遠。可是,它提供了一個叫作minizip的例子給出了操做zip文件的方法。博客
2.minizip簡介it
minizip是zlib的上層庫,它封裝了與zip文件相關的操做。io
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 解壓後的文件