项目展示
项目开发
编译设置
1. Debug/Release编译模式下的编译设置
首先,打开项目工程的属性页,然后将SDK和“平台工具集”选为“你当前的SDK和平台工具集”。
例如我是 SDK 10 平台工具集 v141。
接着,展开“C/C++”,点击“预处理器”,然后在“预处理器定义”中添加“ZLIB_WINAPI”,否则,代码不能编译过去。
接着点击“代码生成”,在“运行库”中设置为“/MTd”选项,表示Debug模式下的多线程静态编译。
接着,展开“链接器”,点击“命令行”,在“其他选项(D)”编辑框中添加链接命令“/FORCE:MULTIPLE” ,这个选项告诉链接器去创建一个有效的exe文件或dll文件,即使一个函数或变量被多次引用或多出定义。
这样,Debug模式下的编译设置就完成了。
设计思路
1. 数据或文件的压缩思路
对于数据或文件的压缩,主要是使用ZLIB库提供的 compress 压缩函数。
int compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
compress函数将source缓冲区中的内容压缩到dest缓冲区。
sourceLen表示source缓冲区的大小(以字节计)。
destLen是传址调用,当调用函数时,destLen表示dest缓冲区大小(初始值不能为0);当函数退出后,destLen表示压缩后缓冲区的实际大小。
返回值:
-5 : 输出缓冲区不够大;
-4 : 没有足够的内存;
0 : 表示成功;
所以,对于文件的压缩,我们根据文件路径,打开文件并读取文件全部数据,然后调用compress函数进行压缩。
其中,需要注意的一个问题便是,对于上述的目的缓冲区的大小难以确定,不能笼统地认为直接使用压缩前文件大小作为压缩后的缓冲区大小。因为,有些小文件,压缩过后,数据可能反而会变大。所以,设计了一个循环,去处理这种情况:
do { iRet = compress(pDestData, &dwDestDataSize, pSrcData, dwFileSize); if (0 == iRet) { // 成功 break; } else if (-5 == iRet) { // 输出缓冲区不够大, 以 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 { // 没有足够的内存 或 其他情况 delete[]pDestData; pDestData = NULL; delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return FALSE; } } while (TRUE);
我们获取compress函数的返回码,判断成功还是出错。
若出错,则判断返回的出错类型,若是返回码为 -5 ,则表示输出缓冲区不够大,这时,便重新申请更大的目的缓冲区,继续调用compress函数压缩数据,继续获取操作返回码。这样,便可解决目的缓冲区大小不明确的问题。
2. 数据或文件的解压缩思路
对于数据或文件的压缩,主要是使用ZLIB库提供的 uncompress 解压缩函数。
int uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
uncompress函数将source缓冲区中的内容压缩到dest缓冲区。
sourceLen表示source缓冲区的大小(以字节计)。
destLen是传址调用,当调用函数时,destLen表示dest缓冲区大小(初始值不能为0);当函数退出后,destLen表示压缩后缓冲区的实际大小。
返回值:
-5 : 输出缓冲区不够大;
-4 : 没有足够的内存;
0 : 表示成功;
所以,对于文件的解压缩,我们根据文件路径,打开文件并读取文件全部数据,然后调用uncompress函数进行解压缩。
针对输出缓冲区大小不明确的问题,我们解决思路也是按照上面数据压缩的解决思路来操作的,同样通过判断uncompress函数操作的返回码,来进行下一步操作。
编码实现
首先将zlib库相关文件放在源目录下
1. 导入ZLIB库文件
//************************************************* // zlib压缩库的头文件和静态库 //************************************************* # 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. 文件压缩
// 数据压缩 // 输入:将要压缩文件的路径 // 输出:数据压缩后的压缩数据内容、数据压缩后的压缩数据内容长度 BOOL Zlib_CompressData(char *pszCompressFileName, BYTE **ppCompressData, DWORD *pdwCompressDataSize) { // 注意可能出现压缩后的文件比压缩前的文件大的现象!!! // 打开文件 并 获取文件数据 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; } // 获取文件大小 DWORD dwFileSize = ::GetFileSize(hFile, NULL); if (MAX_SRC_FILE_SIZE < dwFileSize) { ::CloseHandle(hFile); return FALSE; } // 判断是否满足大小限制条件 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; } // 读取文件数据 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; } // 压缩数据 int iRet = 0; do { iRet = compress(pDestData, &dwDestDataSize, pSrcData, dwFileSize); if (0 == iRet) { // 成功 break; } else if (-5 == iRet) { // 输出缓冲区不够大, 以 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 { // 没有足够的内存 或 其他情况 delete[]pDestData; pDestData = NULL; delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return FALSE; } } while (TRUE); // 返回数据 *ppCompressData = pDestData; *pdwCompressDataSize = dwDestDataSize; delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return TRUE; }
3. 文件解压缩
// 数据解压 // 输入:将要解压缩文件的路径 // 输出:数据解压后的数据内容、数据解压后的内容长度 BOOL Zlib_UncompressData(char *pszUncompressFileName, BYTE **ppUncompressData, DWORD *pdwUncompressDataSize) { // 注意可能出现压缩后的文件比压缩前的文件大的现象!!! // 打开文件 并 获取文件数据 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; } // 获取文件大小 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; } // 读取文件数据 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; } // 解压缩数据 int iRet = 0; do { iRet = uncompress(pDestData, &dwDestDataSize, pSrcData, dwFileSize); if (0 == iRet) { // 成功 break; } else if (-5 == iRet) { // 输出缓冲区不够大, 以 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 { // 没有足够的内存 或 其他情况 delete[]pDestData; pDestData = NULL; delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return FALSE; } } while (TRUE); // 返回数据 *ppUncompressData = pDestData; *pdwUncompressDataSize = dwDestDataSize; delete[]pSrcData; pSrcData = NULL; ::CloseHandle(hFile); return TRUE; }
4. 将数据保存为文件
// 将数据存储为文件 // 输入:数据原文件路径、将要保存的数据内容、将要保存的数据内容长度 BOOL SaveToOriginalFile(char *pszFileName, BYTE *pData, DWORD dwDataSize) { char szSaveName[MAX_PATH] = { 0 }; ::lstrcpy(szSaveName, pszFileName); ::PathStripPath(szSaveName); // 创建文件 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; } // 写入数据 DWORD dwRet = 0; ::WriteFile(hFile, pData, dwDataSize, &dwRet, NULL); // 关闭句柄 ::CloseHandle(hFile); return TRUE; }
程序测试
我们在main函数中,调用上述封装好的函数,对文件进行压缩与解压缩的测试。main函数为:
int _tmain(int argc, _TCHAR* argv[]) { BOOL bRet = FALSE; BYTE *pCompressData = NULL; DWORD dwCompressDataSize = 0; BYTE *pUncompressData = NULL; DWORD dwUncompressDataSize = 0; // 压缩文件 bRet = Zlib_CompressData("test.txt", &pCompressData, &dwCompressDataSize); if (FALSE == bRet) { return 1; } cout << "压缩成功!" << endl; // 保存压缩数据为文件 bRet = SaveToOriginalFile("test.myzip", pCompressData, dwCompressDataSize); if (FALSE == bRet) { return 2; } cout << "保存压缩文件成功!" << endl; // 解压缩压缩文件 bRet = Zlib_UncompressData("test.myzip", &pUncompressData, &dwUncompressDataSize); if (FALSE == bRet) { return 3; } cout << "解压缩成功!" << endl; // 保存压缩数据为文件 bRet = SaveToOriginalFile("test_Uncompress.txt", pUncompressData, dwUncompressDataSize); if (FALSE == bRet) { return 4; } cout << "保存解压缩文件成功!" << endl; // 释放内存 delete []pUncompressData; pUncompressData = NULL; delete []pCompressData; pCompressData = NULL; system("pause"); return 0; }
测试结果为:
可以看到,成功对大小为846KB的test.txt文件的数据进行压缩,得到大小为4KB的test.myzip文件。然后对test.myzip进行解压缩,得到和原来大小一样的test_Uncompress.txt文件。
项目链接
https://download.csdn.net/download/weixin_45525272/40317540