C/C++ Zlib实现文件压缩与解压

在软件开发和数据处理中,对数据进行高效的压缩和解压缩是一项重要的任务。这不仅有助于减小数据在网络传输和存储中的占用空间,还能提高系统的性能和响应速度。本文将介绍如何使用 zlib 库进行数据的压缩和解压缩,以及如何保存和读取压缩后的文件。zlib 是一个开源的数据压缩库,旨在提供高效、轻量级的压缩和解压缩算法。其核心压缩算法基于 DEFLATE,这是一种无损数据压缩算法,通常能够提供相当高的压缩比。zlib 库广泛应用于多个领域,包括网络通信、文件压缩、数据库系统等。

保存文件

使用 CreateFile 打开文件,通过 WriteFile 向文件中写出数据,最后调用 CloseHandle 关闭句柄,实现文件的保存。

#define ZLIB_WINAPI
#include <string>
#include <iostream>
#include <vector>
#include <Shlwapi.h> 
#include <zip.h>
#include <unzip.h>
#include <zlib.h>using namespace std;#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "zlibstat.lib")BOOL SaveToFile(char *pszFileName, BYTE *pData, DWORD dwDataSize)
{char szSaveName[MAX_PATH] = { 0 };lstrcpy(szSaveName, pszFileName);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){return FALSE;}DWORD dwRet = 0;WriteFile(hFile, pData, dwDataSize, &dwRet, NULL);CloseHandle(hFile);return TRUE;
}int main(int argc, char * argv[])
{char szBuffer[1024] = { 0 };strcpy(szBuffer, "test 123123");SaveToFile("d://test.txt", (BYTE *)szBuffer, sizeof(szBuffer));system("pause");return 0;
}

文件压缩

compress 是 zlib 库提供的用于数据压缩的函数,通过该函数可以将数据进行压缩。下面是一个示例,演示了如何使用 zlib 库进行文件压缩。

它的原型如下:

int compress(Bytef* dest, uLongf* destLen, const Bytef* source, uLong sourceLen);
  • dest:指向存放压缩后数据的缓冲区的指针。
  • destLen:传入时为压缩缓冲区的大小,传出时为实际压缩后数据的大小。
  • source:指向待压缩数据的缓冲区的指针。
  • sourceLen:待压缩数据的大小。

compress 函数的作用是将 source 指向的数据进行压缩,并将结果存放在 dest 指向的缓冲区中。destLen 传入时应该是 dest 缓冲区的大小,函数执行后,destLen 会更新为实际压缩后数据的大小。

函数返回值为压缩的执行状态,可能的返回值包括:

  • Z_OK:压缩成功。
  • Z_MEM_ERROR:内存分配失败。
  • Z_BUF_ERROR:压缩输出缓冲区不足。

这个函数实际上是使用 DEFLATE 算法进行压缩,DEFLATE 是一种通用的压缩算法,也是 zlib 库的核心算法之一。压缩后的数据可以使用 uncompress 函数进行解压缩。

总体而言,compress 函数提供了一种简单的方式,可以在应用程序中对数据进行压缩,适用于需要减小数据体积的场景,比如网络传输或数据存储。

// 单个文件限制大小为 100M 
#define MAX_SRC_FILE_SIZE (100*1024*1024)/*** @brief 压缩指定文件的数据** @param pszCompressFileName 待压缩文件的路径* @param ppCompressData 保存压缩后数据的指针* @param pdwCompressDataSize 传入时为压缩缓冲区的大小,传出时为实际压缩后数据的大小* @return 压缩是否成功,成功返回 TRUE,否则返回 FALSE*/
BOOL 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){return FALSE;}// 获取文件大小DWORD dwFileSize = GetFileSize(hFile, NULL);// 检查文件大小是否超过限制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){delete[] pSrcData;CloseHandle(hFile);return FALSE;}DWORD dwRet = 0;// 读取源数据ReadFile(hFile, pSrcData, dwFileSize, &dwRet, NULL);// 检查读取是否成功if ((0 >= dwRet) || (dwRet != dwFileSize)){delete[] pDestData;delete[] pSrcData;CloseHandle(hFile);return FALSE;}int iRet = 0;// 压缩数据do{iRet = compress(pDestData, &dwDestDataSize, pSrcData, dwFileSize);// 压缩成功,退出循环if (0 == iRet){break;}// 输出缓冲区不足,增加缓冲区大小并重试else if (-5 == iRet){delete[] pDestData;pDestData = NULL;dwDestDataSize = dwDestDataSize + (100 * 1024);pDestData = new BYTE[dwDestDataSize];// 分配新的目标数据内存if (NULL == pDestData){delete[] pSrcData;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;// 关闭文件句柄CloseHandle(hFile);// 返回压缩成功return TRUE;
}

文件解压缩

uncompress 函数是 zlib 库提供的用于数据解压缩的函数,通过该函数可以将压缩后的数据解压缩还原。下面是一个示例,演示了如何使用 zlib 库进行文件解压缩。

它的原型如下:

int uncompress(Bytef* dest, uLongf* destLen, const Bytef* source, uLong sourceLen);
  • dest:指向存放解压缩后数据的缓冲区的指针。
  • destLen:传入时为解压缩缓冲区的大小,传出时为实际解压缩后数据的大小。
  • source:指向待解压缩数据的缓冲区的指针。
  • sourceLen:待解压缩数据的大小。

uncompress 函数的作用是将 source 指向的数据进行解压缩,并将结果存放在 dest 指向的缓冲区中。destLen 传入时应该是 dest 缓冲区的大小,函数执行后,destLen 会更新为实际解压缩后数据的大小。

函数返回值为解压缩的执行状态,可能的返回值包括:

  • Z_OK:解压缩成功。
  • Z_MEM_ERROR:内存分配失败。
  • Z_BUF_ERROR:解压缩输出缓冲区不足。
  • Z_DATA_ERROR:输入数据错误或损坏。

uncompress 函数实际上是使用 DEFLATE 算法进行解压缩,与 compress 函数相对应。这两个函数共同构成了 zlib 库中的基本数据压缩和解压缩功能。

在实际应用中,可以使用这两个函数来处理需要压缩和解压缩的数据,例如在网络通信中减小数据传输量或在存储数据时减小占用空间。

/*** @brief 解压指定文件的数据** @param pszUncompressFileName 待解压文件的路径* @param ppUncompressData 保存解压后数据的指针* @param pdwUncompressDataSize 传入时为解压缓冲区的大小,传出时为实际解压后数据的大小* @return 解压是否成功,成功返回 TRUE,否则返回 FALSE*/
BOOL 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){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){delete[] pSrcData;CloseHandle(hFile);return FALSE;}DWORD dwRet = 0;// 读取源数据ReadFile(hFile, pSrcData, dwFileSize, &dwRet, NULL);// 检查读取是否成功if ((0 >= dwRet) || (dwRet != dwFileSize)){delete[] pDestData;delete[] pSrcData;CloseHandle(hFile);return FALSE;}int iRet = 0;// 解压缩数据do{iRet = uncompress(pDestData, &dwDestDataSize, pSrcData, dwFileSize);// 解压缩成功,退出循环if (0 == iRet){break;}// 输出缓冲区不足,增加缓冲区大小并重试else if (-5 == iRet){delete[] pDestData;pDestData = NULL;dwDestDataSize = dwDestDataSize + (100 * 1024);pDestData = new BYTE[dwDestDataSize];// 分配新的目标数据内存if (NULL == pDestData){delete[] pSrcData;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;// 关闭文件句柄CloseHandle(hFile);// 返回解压成功return TRUE;
}

演示示例

下面是一个包含文件压缩和解压缩的完整示例,展示了如何将文件进行压缩保存,然后解压还原。

调用CompressData压缩文件,返回结果pCompressData存放文件内存字节,结果dwCompressDataSize存放长度,并调用SaveToFile保存到本地。

int main(int argc, char* argv[])
{BOOL bRet = FALSE;BYTE *pCompressData = NULL;DWORD dwCompressDataSize = 0;// 压缩文件bRet = CompressData("d:\\test.exe", &pCompressData, &dwCompressDataSize);if (TRUE == bRet){std::cout << "已压缩" << std::endl;}// 保存压缩数据为文件bRet = SaveToFile("d:\\text.zlib", pCompressData, dwCompressDataSize);if (TRUE == bRet){std::cout << "已保存到文件" << std::endl;}// 释放内存delete[]pCompressData;pCompressData = NULL;system("pause");return 0;
}

调用UncompressData解压缩文件,返回结果pUncompressData存放文件内存字节,结果dwUncompressDataSize存放长度,并调用SaveToFile保存到本地。

int main(int argc, char* argv[])
{BOOL bRet = FALSE;BYTE *pUncompressData = NULL;DWORD dwUncompressDataSize = 0;// 解压文件bRet = UncompressData("d:\\test.zlib", &pUncompressData, &dwUncompressDataSize);if (TRUE == bRet){std::cout << "已解压" << std::endl;}// 保存解压数据为文件bRet = SaveToFile("d:\\test.exe", pUncompressData, dwUncompressDataSize);if (TRUE == bRet){std::cout << "已保存到文件" << std::endl;}// 释放内存delete[]pUncompressData;pUncompressData = NULL;system("pause");return 0;
}

编译时可能会提示无法生成SAFESEH影响的报错信息,如下图所示;

此时打开项目属性页,找到链接器,高级选项卡,将映像安全处理改为否即可,如下图所示;

结论

通过使用 zlib 库,我们可以方便地在应用程序中实现数据的压缩和解压缩功能。这对于需要减小数据传输量或在存储数据时减小占用空间的场景非常有用。在实际应用中,可以根据需要调整缓冲区大小和处理流程,以适应不同的数据处理需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/225045.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用C++和python混合编写数据采集程序?

之前看过一篇文章&#xff0c;主要阐述的就是多种语言混合编写爬虫程序&#xff0c;结合各种语言自身优势写一个爬虫代码是否行得通&#xff1f;觉得挺有意思的&#xff0c;带着这样的问题&#xff0c;我尝试着利用我毕生所学写了一段C和python混合爬虫程序&#xff0c;目前运行…

电脑如何录音?适合初学者的详细教程

“电脑怎么录音呀&#xff1f;参加了一个学校举办的短视频大赛&#xff0c;视频拍摄都很顺利&#xff0c;音乐却出了问题&#xff0c;朋友说可以用电脑录制一段音乐应付一下&#xff0c;可是我不会操作&#xff0c;有哪位大佬教教我&#xff01;” 声音是一种强大的媒介&#…

“全球金牌课程”1 月 13-14 日 · CSM 认证在线面授周末班【模块化教学】CST 导师亲授

课堂互动练习 CSM 认证在线培训&#xff08;周末班&#xff09; 2024 年 1 月 13-14 日 Zoom 在线面授&#xff0c;全国招生 讲师: Jim Wang 王军 10 年以上 CSM/CSPO 认证课程教学交付经验&#xff0c; 5 年以上 A-CSM/CSP-SM 认证课程教学交付经验&#xff0c; 国际 Scr…

tabs切换,当点击tabItem时候,改变选中样式,以及content内容区域

效果图展示&#xff1a; html原生代码&#xff1a; <div><div class"buttons-row nav-select riskType" style"padding: 10px;"><div class"shoucang-title-box flex-start"><div class"shoucang-title-item active&q…

docker-compose Install OrangeHRM

OrangeHRM 前言 OrangeHRM 是一个全面的人力资源管理(HRM) 系统,它包含任何企业所需的所有基本功能。OrangeHRM旨在支持任何规模的团队,包括初创企业、中小企业以及大型跨国组织。 OrangeHRM 提前条件 OrangeHRMdocker & docker-composer 安装or

Scanner常用知识点

在Java中&#xff0c;Scanner类是用于读取用户输入的工具类&#xff0c;可以从多种输入源读取数据&#xff0c;如标准输入流、文件或字符串。以下是一些Scanner类的常用知识点&#xff1a; Scanner的初始化&#xff1a;在使用Scanner类之前&#xff0c;需要先将其导入到你的Ja…

Python实现WOA智能鲸鱼优化算法优化LightGBM分类模型(LGBMClassifier算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 鲸鱼优化算法 (whale optimization algorithm,WOA)是 2016 年由澳大利亚格里菲斯大学的Mirjalili 等提…

基于Eclipse+Tomcat+Mysql开发的二手交易市场

基于Eclipse开发的二手交易市场 项目介绍&#x1f481;&#x1f3fb; 随着互联网的普及和发展&#xff0c;越来越多的人开始使用网络进行购物。二手交易网站作为一种新型的电子商务模式&#xff0c;为用户提供了一个便捷、安全、可靠的交易平台。在这个平台上&#xff0c;用户可…

[ACTF2020 新生赛]BackupFile

打开题目就一句话&#xff1a;尝试找到源文件 和上一题一样&#xff0c;用dirsearch扫描网站找到了一下内容 flag.php&#xff0c;0B&#xff0c;虚假flag 瞅一眼index.php.bak是啥 下载了一个文件&#xff0c;把bak后缀删掉&#xff0c;打开了index.php源码 is_numeric()&am…

excel单元格内换行按什么快捷键

如果我们使用excel软件的时候&#xff0c;因为一些日常的操作太过繁琐想要简化自己的操作步骤的话&#xff0c;其实是有很多快捷方式在其中的。那么对excel单元格内换行按什么快捷键这个问题&#xff0c;据小编所知我们可以在表格中使用Alt Enter来进行换行。详细内容就来看下…

亚信科技AntDB数据库与库瀚存储方案完成兼容性互认证

近日&#xff0c;亚信科技AntDB数据库与苏州库瀚信息科技有限公司自主研发的RISC-V数据库存储解决方案进行了产品兼容测试。经过双方团队的严格测试&#xff0c;亚信科技AntDB数据库与库瀚数据库存储解决方案完全兼容、运行稳定。除高可用性测试外&#xff0c;双方进一步开展TP…

kaggle使用matplotlib画图中文乱码问题解决

import matplotlib import matplotlib.pyplot as plt myfont matplotlib.font_manager.FontProperties(fnamer/kaggle/input/flux-predict/STFANGSO/STFANGSO.TTF) train_corr df_train.corr() k 6 cols train_corr.nlargest(k,4G流量MB&#xff08;1024&#xff09;(兆字…