zlib庫編譯過程遇到的問題及其使用zlib庫進行解壓縮

Quellaaa發表於2018-08-05

目錄

1. 下載zlib

2. 編譯zlib

3. 使用zlib庫解壓檔案

    3.1 準備工作

    3.2 使用解壓函式對檔案進行解壓


1. 下載zlib

可以去官網http://www.zlib.net/ 下載zlib

2. 編譯zlib

ps:此處執行環境為VS2008+zlib1.2.7

step1:開啟VS2008的命令列執行視窗

step2:開啟命令列視窗後,進入zlib-1.2.7\contrib\masmx86目錄,輸入bld_ml32.bat命令,按下Enter鍵執行該命令

出現上述訊息說明編譯成功。

PS:由於現在機器基本都是64位,所以一般都是進入masmx64目錄,執行bld_ml64.bat。但由於我在Win7和Win10系統環境下執行時出現“ml64.exe不是內部或外部命令,也不是可執行的程式”錯誤,錯誤如下圖所示,由於作業系統內部會自動將32位軟體地址向64位地址對齊,因此在64位機器上使用32位軟體沒問題!綜上,我們這裡編譯bld_ml32.bat~

step3:進入目錄D:\zlib-1.2.7\contrib\vstudio\vc9,由於我使用的是vs2008執行,所以進入的是vc9目錄。接著用vs2008開啟zlibvc.sln

step4:vs2008開啟該檔案後,首先要將該專案屬性的前處理器設定為win32,然後編譯該專案(按一下F5~)

step5:此時D:\zlib-1.2.7\contrib\vstudio\vc9\x86目錄下就出現了一個ZlibDllDebug資料夾,裝有編譯好的dll庫和lib

以上zlib庫編譯完成~


3. 使用zlib庫解壓檔案

3.1 準備工作

要在專案中使用zlib庫解壓檔案,需要先做一些準備工作~在要使用zlib庫的專案檔案中新建一個資料夾,這裡我命名為zlib,裡面的檔案有:(由於這裡只是使用zlib庫解壓,所以包含以下檔案足以夠用)

此時還需要將zlibwapi.dll放到windows/System中,不然執行時會報錯~

最後只需在專案程式碼中加入這兩行程式碼即可~

    #include "zlib/unzip.h"
    #pragma comment(lib, "zlib/zlibwapi.lib") 

以上準備工作完成,接下來可以在程式碼中使用zlib庫的函式對檔案進行解壓啦~ 

3.2 使用解壓函式對檔案進行解壓

1)開啟壓縮檔案。利用unzOpen64(char* filePath)函式開啟壓縮檔案,其返回值若為NULL則說明開啟壓縮檔案失敗;否則返回開啟unzFile型別的變數說明成功開啟壓縮檔案。

2)獲取壓縮檔案的全域性訊息。利用unzGetGlobalInfo64(unzFile zFile, unz_global_info64 *zGlobalInfo)函式獲取壓縮檔案的全域性訊息,放到unz_global_info64結構體中,其中有個重要的成員變數——壓縮檔案內所有檔案的數量,但不包括目錄。因此可以利用該函式得知壓縮檔案內的檔案數量。

3)迴圈遍歷壓縮檔案內的所有檔案,並將壓縮檔案解壓到本地檔案中(其實這就是將讀取到的檔案寫到本地檔案中,從而完成解壓)。

    	//遍歷所有檔案
        unz_file_info64 zFileInfo;
	unsigned int num = 512;
	char *fileName = new char[num];
	char *fileData = new char[500*1024];

        // zGlobalInfo.number_entry就是獲取壓縮檔案的所有檔案數量
	for(int i=0; i < zGlobalInfo.number_entry; i++)
	{
		// 獲得壓縮檔案裡的檔案(下稱為當前壓縮檔案)資訊(其中fileName是全路徑名)
		if(UNZ_OK != unzGetCurrentFileInfo64(zFile,&zFileInfo,fileName,num,NULL,0,NULL,0))
		{
			cout<<"得到當前檔案資訊出錯"<<endl;
			return ;
		}
                // 開啟當前壓縮檔案
		if(UNZ_OK != unzOpenCurrentFile(zFile))
		{
			cout<<"開啟壓縮包中"<<fileName<<"檔案失敗"<<endl;
			return ;
		}
                // 壓縮檔案全域性資訊結構體中的成員變數——未解壓前檔案的大小
		int fileLength = zFileInfo.uncompressed_size;
		
		//解壓縮檔案
                // 讀取當前壓縮檔案,返回值為讀取的位元組長
                int len;
		len = unzReadCurrentFile(zFile,(voidp)fileData,fileLength);
		fileData[len] = '\0';

		//寫入到本地解壓縮後的檔案中 
                // 由於ofstream不能建立帶/的檔名,而fileName是絕對路徑,包括/,因此要先對fileName字串分割,獲得最後一個/後面的檔名,這才是我們所需要的解壓後檔名
		std::string strFileName = fileName;
		int nLength = strFileName.length();
		int nPos ;
		nPos = strFileName.find_last_of("/", nLength);
		std::string strPath = strFileName.substr(nPos+1, nLength);
		std::ofstream file(strPath.c_str(),std::ios::out|std::ios::binary);

		if(!file.good())
		{
			cout<<"file not good"<<endl;
			return ;
		}
                // 將指標定位到檔案的一開始
		file.seekp(0,std::ios::beg);
		file.write(fileData,len);
		file.close();
                // 關閉當前解壓檔案
		unzCloseCurrentFile(zFile);
                // 下一個解壓檔案
		unzGoToNextFile(zFile);
	}
	unzClose(zFile);
	delete[] fileData;

完整解壓程式碼如下:

void unzip(LPCTSTR szSavePath)
{
	unzFile zFile;
	// Unicode轉為ANSI
	char filePath[MAX_PATH];
	WideCharToMultiByte(CP_ACP, 0, szSavePath, -1, filePath, MAX_PATH, NULL, NULL);
	// 開啟壓縮檔案
	zFile = unzOpen64(filePath);
	if (zFile == NULL)
	{
		//MessageBox(L"開啟壓縮檔案失敗");
		return;
	}

	// 獲取壓縮檔案的全域性訊息
	unz_global_info64 zGlobalInfo; 
	// 重要成員變數是壓縮檔案內所有檔案的數量(不包括目錄)
	if (UNZ_OK != unzGetGlobalInfo64(zFile, &zGlobalInfo))
	{
		//OutputDebugString(__FILE__ + L"中"+__LINE__+L"行錯誤,得到全域性資訊出錯");
		return;
	}

	// 迴圈遍歷所有檔案
	unz_file_info64 zFileInfo;
	unsigned int num = 512;
	char *fileName = new char[num];
	char *fileData = new char[500*1024];

	for(int i=0; i < zGlobalInfo.number_entry; i++)
	{
		//遍歷所有檔案(fileName是全路徑名)
		if(UNZ_OK != unzGetCurrentFileInfo64(zFile,&zFileInfo,fileName,num,NULL,0,NULL,0))
		{
			//cout<<"得到當前檔案資訊出錯"<<endl;
			return ;
		}
		if(UNZ_OK != unzOpenCurrentFile(zFile))
		{
			//cout<<"開啟壓縮包中"<<fileName<<"檔案失敗"<<endl;
			return ;
		}
		int fileLength = zFileInfo.uncompressed_size;
		int len;
		//解壓縮檔案
		len = unzReadCurrentFile(zFile,(voidp)fileData,fileLength);
		fileData[len] = '\0';
		//寫入到解壓縮後的檔案中 
		std::string strFileName = fileName;
		int nLength = strFileName.length();
		int nPos ;
		nPos = strFileName.find_last_of("/", nLength);
		std::string strPath = strFileName.substr(nPos+1, nLength);
		std::ofstream file(strPath.c_str(),std::ios::out|std::ios::binary);

		if(!file.good())
		{
			//cout<<"file not good"<<endl;
			return ;
		}
		file.seekp(0,std::ios::beg);
		file.write(fileData,len);
		file.close();
		unzCloseCurrentFile(zFile);
		unzGoToNextFile(zFile);
	}
	unzClose(zFile);
	delete[] fileData;
}

 

相關文章