Project display
Project development
Compilation settings
1. Compilation settings in debug / release compilation mode
First, open the property page of the project, and then select SDK and platform toolset as your current SDK and platform toolset.
For example, I am SDK 10 platform toolset v141.
Then, expand "C/C + +", click "preprocessor", and then add "ZLIB_WINAPI" to "preprocessor definition". Otherwise, the code cannot be compiled.
Then click "code generation" and set the "/ MTd" option in "runtime" to indicate multi-threaded static compilation in Debug mode.
Then, expand "linker", click "command line", and add the link command "/ FORCE:MULTIPLE" in the "other options (D)" edit box. This option tells the linker to create a valid exe file or dll file, even if a function or variable is referenced multiple times or defined more than once.
In this way, the compilation setting in Debug mode is completed.
Design ideas
1. Compression of data or files
For data or file compression, the compress compression function provided by ZLIB library is mainly used.
int compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
The compress function compresses the contents of the source buffer into the dest buffer.
sourceLen indicates the size of the source buffer in bytes.
destLen is an address transfer call. When calling a function, destLen represents the dest buffer size (the initial value cannot be 0); When the function exits, destLen represents the actual size of the compressed buffer.
Return value:
-5: the output buffer is not large enough;
-4: not enough memory;
0: indicates success;
So, for file compression, we open the file and read all the data according to the file path, then call the compress function to compress it.
Among them, one problem that needs to be noted is that it is difficult to determine the size of the above destination buffer, and it can not be generally considered that the file size before compression is directly used as the buffer size after compression. Because for some small files, the data may become larger after compression. Therefore, a loop is designed to deal with this situation:
do { iRet = compress(pDestData, &dwDestDataSize, pSrcData, dwFileSize); if (0 == iRet) { // success break; } else if (-5 == iRet) { // The output buffer is not large enough, increasing by 100KB delete[]pDestData; pDestData = NULL; dwDestDataSize = dwDestDataSize + (100 * 1024); pDestData = new BYTE[dwDestDataSize]; if (NULL == pDestData) { delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return FALSE; } } else { // Not enough memory or other conditions delete[]pDestData; pDestData = NULL; delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return FALSE; } } while (TRUE);
We get the return code of the compress function to determine whether it is successful or wrong.
If there is an error, judge the error type returned. If the return code is - 5, it means that the output buffer is not large enough. At this time, re apply for a larger destination buffer, continue to call the compress function to compress the data, and continue to obtain the operation return code. In this way, the problem of ambiguous destination buffer size can be solved.
2. Decompression ideas of data or files
For data or file compression, the uncompress decompression function provided by ZLIB library is mainly used.
int uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
The uncompress function compresses the contents of the source buffer into the dest buffer.
sourceLen indicates the size of the source buffer in bytes.
destLen is an address transfer call. When calling a function, destLen represents the dest buffer size (the initial value cannot be 0); When the function exits, destLen represents the actual size of the compressed buffer.
Return value:
-5: the output buffer is not large enough;
-4: not enough memory;
0: indicates success;
So, for file decompression, we open the file and read all the data according to the file path, then call the uncompress function to decompress it.
To solve the problem of unclear output buffer size, we also operate according to the above solution of data compression. Similarly, we judge the return code of uncompress function operation to carry out the next operation.
Coding implementation
First, put the zlib library related files in the source directory
1. Import ZLIB library file
//************************************************* // zlib compressed library header files and static libraries //************************************************* # include "zlib\\zconf.h" # include "zlib\\zlib.h" # ifdef _DEBUG #ifdef _WIN64 #pragma comment(lib, "zlib\\x64\\debug\\zlibstat.lib") #else #pragma comment(lib, "zlib\\x86\\debug\\zlibstat.lib") #endif # else #ifdef _WIN64 #pragma comment(lib, "zlib\\x64\\release\\zlibstat.lib") #else #pragma comment(lib, "zlib\\x86\\release\\zlibstat.lib") #endif # endif //*************************************************
2. File compression
// data compression // Enter: the path of the file to be compressed // Output: compressed data content after data compression, length of compressed data content after data compression BOOL Zlib_CompressData(char *pszCompressFileName, BYTE **ppCompressData, DWORD *pdwCompressDataSize) { // Note that the compressed file may be larger than the file before compression!!! // Open the file and get the file data HANDLE hFile = ::CreateFile(pszCompressFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL); if (INVALID_HANDLE_VALUE == hFile) { Zlib_ShowError("CreateFile"); return FALSE; } // Get file size DWORD dwFileSize = ::GetFileSize(hFile, NULL); if (MAX_SRC_FILE_SIZE < dwFileSize) { ::CloseHandle(hFile); return FALSE; } // Judge whether the size limit conditions are met if (MAX_SRC_FILE_SIZE < dwFileSize) { ::CloseHandle(hFile); return FALSE; } DWORD dwDestDataSize = dwFileSize; BYTE *pSrcData = new BYTE[dwFileSize]; if (NULL == pSrcData) { ::CloseHandle(hFile); return FALSE; } BYTE *pDestData = new BYTE[dwDestDataSize]; if (NULL == pDestData) { ::CloseHandle(hFile); return FALSE; } // Read file data DWORD dwRet = 0; ::ReadFile(hFile, pSrcData, dwFileSize, &dwRet, NULL); if ((0 >= dwRet) || (dwRet != dwFileSize)) { delete[]pDestData; pDestData = NULL; delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return FALSE; } // compressed data int iRet = 0; do { iRet = compress(pDestData, &dwDestDataSize, pSrcData, dwFileSize); if (0 == iRet) { // success break; } else if (-5 == iRet) { // The output buffer is not large enough, increasing by 100KB delete[]pDestData; pDestData = NULL; dwDestDataSize = dwDestDataSize + (100 * 1024); pDestData = new BYTE[dwDestDataSize]; if (NULL == pDestData) { delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return FALSE; } } else { // Not enough memory or other conditions delete[]pDestData; pDestData = NULL; delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return FALSE; } } while (TRUE); // Return data *ppCompressData = pDestData; *pdwCompressDataSize = dwDestDataSize; delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return TRUE; }
3. File decompression
// Data decompression // Enter: the path of the file to be uncompressed // Output: data content after data decompression and content length after data decompression BOOL Zlib_UncompressData(char *pszUncompressFileName, BYTE **ppUncompressData, DWORD *pdwUncompressDataSize) { // Note that the compressed file may be larger than the file before compression!!! // Open the file and get the file data HANDLE hFile = ::CreateFile(pszUncompressFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL); if (INVALID_HANDLE_VALUE == hFile) { Zlib_ShowError("CreateFile"); return FALSE; } // Get file size DWORD dwFileSize = ::GetFileSize(hFile, NULL); DWORD dwDestDataSize = MAX_SRC_FILE_SIZE; BYTE *pSrcData = new BYTE[dwFileSize]; if (NULL == pSrcData) { ::CloseHandle(hFile); return FALSE; } BYTE *pDestData = new BYTE[dwDestDataSize]; if (NULL == pDestData) { ::CloseHandle(hFile); return FALSE; } // Read file data DWORD dwRet = 0; ::ReadFile(hFile, pSrcData, dwFileSize, &dwRet, NULL); if ((0 >= dwRet) || (dwRet != dwFileSize)) { delete[]pDestData; pDestData = NULL; delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return FALSE; } // Decompress data int iRet = 0; do { iRet = uncompress(pDestData, &dwDestDataSize, pSrcData, dwFileSize); if (0 == iRet) { // success break; } else if (-5 == iRet) { // The output buffer is not large enough, increasing by 100KB delete[]pDestData; pDestData = NULL; dwDestDataSize = dwDestDataSize + (100 * 1024); pDestData = new BYTE[dwDestDataSize]; if (NULL == pDestData) { delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return FALSE; } } else { // Not enough memory or other conditions delete[]pDestData; pDestData = NULL; delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return FALSE; } } while (TRUE); // Return data *ppUncompressData = pDestData; *pdwUncompressDataSize = dwDestDataSize; delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return TRUE; }
4. Save data as a file
// Store data as a file // Input: Data original file path, data content to be saved, and length of data content to be saved BOOL SaveToOriginalFile(char *pszFileName, BYTE *pData, DWORD dwDataSize) { char szSaveName[MAX_PATH] = { 0 }; ::lstrcpy(szSaveName, pszFileName); ::PathStripPath(szSaveName); // create a file HANDLE hFile = ::CreateFile(szSaveName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL); if (INVALID_HANDLE_VALUE == hFile) { Zlib_ShowError("CreateFile"); return FALSE; } // Write data DWORD dwRet = 0; ::WriteFile(hFile, pData, dwDataSize, &dwRet, NULL); // Close handle ::CloseHandle(hFile); return TRUE; }
Program test
In the main function, we call the encapsulated function to test the compression and decompression of files. The main function is:
int _tmain(int argc, _TCHAR* argv[]) { BOOL bRet = FALSE; BYTE *pCompressData = NULL; DWORD dwCompressDataSize = 0; BYTE *pUncompressData = NULL; DWORD dwUncompressDataSize = 0; // Compressed file bRet = Zlib_CompressData("test.txt", &pCompressData, &dwCompressDataSize); if (FALSE == bRet) { return 1; } cout << "Compression succeeded!" << endl; // Save compressed data as a file bRet = SaveToOriginalFile("test.myzip", pCompressData, dwCompressDataSize); if (FALSE == bRet) { return 2; } cout << "Compressed file saved successfully!" << endl; // Decompress the compressed file bRet = Zlib_UncompressData("test.myzip", &pUncompressData, &dwUncompressDataSize); if (FALSE == bRet) { return 3; } cout << "Decompression succeeded!" << endl; // Save compressed data as a file bRet = SaveToOriginalFile("test_Uncompress.txt", pUncompressData, dwUncompressDataSize); if (FALSE == bRet) { return 4; } cout << "Successfully saved the extracted file!" << endl; // Free memory delete []pUncompressData; pUncompressData = NULL; delete []pCompressData; pCompressData = NULL; system("pause"); return 0; }
The test results are:
You can see that the data of the test.txt file with the size of 846KB is successfully compressed to obtain the test.myzip file with the size of 4KB. Then decompress test.myzip to get the same size as the original test_Uncompress.txt file.