C + + data or file compression and decompression reduction program based on ZLIB compression library

Keywords: C++ Mini Program Visual Studio

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.

Project link

https://download.csdn.net/download/weixin_45525272/40317540

Posted by DevilsAdvocate on Thu, 11 Nov 2021 09:56:12 -0800