背景

对于Windows上的数据压缩和解压缩的实现,最方便的就是直接调用Win32 API函数。Widnows系统的ntdll.dll专门提供了RtlCompressBuffer函数和RtlDecompressBuffer函数来负责对数据压缩和解压缩操作,这两个函数并未公开,需要通过在ntdll.dll中动态调用。

函数介绍

RtlGetCompressionWorkSpaceSize

// 确定缓冲区大小
// 返回STATUS_SUCCESS,则表示成功;否则,失败NTSTATUS RtlGetCompressionWorkSpaceSize(_In_  USHORT CompressionFormatAndEngine,        // 位掩码指定压缩格式和引擎类型_Out_ PULONG CompressBufferWorkSpaceSize,      // 接收压缩缓冲区所需的大小_Out_ PULONG CompressFragmentWorkSpaceSize   // 接收将压缩缓冲区解压缩为片段所需的大小);

RtlCompressBuffer

// 压缩一个缓冲区
// 返回STATUS_SUCCESS,则表示成功;否则,失败。NTSTATUS RtlCompressBuffer(_In_  USHORT CompressionFormatAndEngine,        // 指定压缩格式和引擎类型的位掩码_In_  PUCHAR UncompressedBuffer,              // 指向要压缩的数据缓冲区的指针_In_  ULONG  UncompressedBufferSize,           // UncompressedBuffer 缓冲区的大小_Out_ PUCHAR CompressedBuffer,              // 指向压缩之后的数据缓存的缓冲区的指针,用于接收压缩数据_In_  ULONG  CompressedBufferSize,         // CompressedBuffer缓冲区的大小_In_  ULONG  UncompressedChunkSize,            // 压缩UncompressedBuffer缓冲区时使用的块大小(512、1024、2048或4096)_Out_ PULONG FinalCompressedSize,              // 指向调用方分配变量的指针,该变量接收存储在CompressedBuffer中的压缩数据的大小_In_  PVOID  WorkSpace                      // 指向压缩期间RtlCompressBuffer函数使用的调用方分配的工作空间缓冲区的指针);

RtlDecompressBuffer

// 解压缩整个压缩缓冲区。
// 返回STATUS_SUCCESS,则表示成功;否则,失败。NTSTATUS RtlDecompressBuffer(_In_  USHORT CompressionFormat,           // 指定压缩缓冲区压缩格式的位掩码_Out_ PUCHAR UncompressedBuffer,          // 指向存储解压缩数据的缓冲区的指针,该缓冲区从CompressedBuffer接收解压缩的数据_In_  ULONG  UncompressedBufferSize,        // UncompressedBuffer缓冲区的大小_In_  PUCHAR CompressedBuffer,           // 指向包含要解压缩的数据的缓冲区的指针_In_  ULONG  CompressedBufferSize,     // CompressedBuffer缓冲区的大小_Out_ PULONG FinalUncompressedSize     // 指向解压之后得到的数据大小的指针,该变量接收UncompressedBuffer中存储的解压缩数据的大小);

实现过程

数据压缩主要是通过调用RtlCompressBuffer函数来实现的,那么,具体的数据压缩实现流程如下所示。

首先,先调用LoadLibrary函数加载ntdll.dll,并获取ntdll.dll加载模块的句柄。再调用GetProcAddress函数来获取RtlGetCompressionWorkSpaceSize函数以及RtlCompressBuffer函数。

然后,直接调用RtlGetCompressionWorkSpaceSize函数来获取RtlCompressBuffer函数工作空间缓冲区的大小。其中,压缩格式和引擎类型设置为COMPRESSION_FORMAT_LZNT1和COMPRESSION_ENGINE_STANDARD。然后,根据工作空间缓冲区大小申请一个工作空间缓冲区给压缩数据使用。

最后,调用RtlCompressBuffer函数来压缩数据。数据压缩缓冲区的大小为4096字节,在成功压缩数据之后,便获取实际的压缩数据大小。此时需要将实际压缩数据大小和数据压缩缓冲区大小进行比较,如果数据压缩缓冲区太小,则需要释放原来的缓冲区,重新按照实际压缩数据的大小来申请一个新的数据压缩缓冲区,并且重新压缩数据。这样,才能获取所有的压缩数据。

那么,使用RtlCompressBuffer函数压缩数据的具体实现代码如下所示。

    // 数据压缩BOOL CompressData(BYTE *pUncompressData, DWORD dwUncompressDataLength, BYTE **ppCompressData, DWORD *pdwCompressDataLength){BOOL bRet = FALSE;NTSTATUS status = 0;HMODULE hModule = NULL;typedef_RtlGetCompressionWorkSpaceSize RtlGetCompressionWorkSpaceSize  = NULL;typedef_RtlCompressBuffer RtlCompressBuffer = NULL;DWORD dwWorkSpaceSize = 0, dwFragmentWorkSpaceSize = 0;BYTE *pWorkSpace = NULL;BYTE *pCompressData = NULL;DWORD dwCompressDataLength = 4096;DWORD dwFinalCompressSize = 0;do{// 加载 ntdll.dll hModule = ::LoadLibrary("ntdll.dll");if (NULL == hModule){ShowError("LoadLibrary");break;}// 获取 RtlGetCompressionWorkSpaceSize 函数地址RtlGetCompressionWorkSpaceSize = (typedef_RtlGetCompressionWorkSpaceSize)::GetProcAddress(hModule, "RtlGetCompressionWorkSpaceSize");if (NULL == RtlGetCompressionWorkSpaceSize){ShowError("GetProcAddress");break;}// 获取 RtlCompressBuffer 函数地址RtlCompressBuffer = (typedef_RtlCompressBuffer)::GetProcAddress(hModule, "RtlCompressBuffer");if (NULL == RtlCompressBuffer){ShowError("GetProcAddress");break;}// 获取WorkSpqce大小status = RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_LZNT1 | COMPRESSION_ENGINE_STANDARD, &dwWorkSpaceSize, &dwFragmentWorkSpaceSize);if (0 != status){ShowError("RtlGetCompressionWorkSpaceSize");break;}// 申请动态内存pWorkSpace = new BYTE[dwWorkSpaceSize];if (NULL == pWorkSpace){ShowError("new");break;}::RtlZeroMemory(pWorkSpace, dwWorkSpaceSize);while (TRUE){// 申请动态内存pCompressData = new BYTE[dwCompressDataLength];if (NULL == pCompressData){ShowError("new");break;}::RtlZeroMemory(pCompressData, dwCompressDataLength);// 调用RtlCompressBuffer压缩数据RtlCompressBuffer(COMPRESSION_FORMAT_LZNT1, pUncompressData, dwUncompressDataLength, pCompressData, dwCompressDataLength, 4096, &dwFinalCompressSize, (PVOID)pWorkSpace);if (dwCompressDataLength < dwFinalCompressSize){// 释放内存if (pCompressData){delete[]pCompressData;pCompressData = NULL;}dwCompressDataLength = dwFinalCompressSize;}else{break;}}// 返回*ppCompressData = pCompressData;*pdwCompressDataLength = dwFinalCompressSize;bRet = TRUE;} while(FALSE);// 释放if (pWorkSpace){delete[]pWorkSpace;pWorkSpace = NULL;}if (hModule){::FreeLibrary(hModule);}return bRet;}

数据解压缩主要是通过调用RtlDecompressBuffer函数来实现的,相比于数据压缩,数据解压缩实现起来更为简单。那么,具体的数据解压缩实现流程如下所示。

首先,同样是先调用LoadLibrary函数加载ntdll.dll,并获取ntdll.dll加载模块的句柄。再调用GetProcAddress函数RtlDecompressBuffer函数。不需要获取RtlGetCompressionWorkSpaceSize函数的地址,因为数据解压缩操作不需要确定压缩工作空间缓冲区大小

然后,开始调用RtlDecompressBuffer函数来解压缩数据。其中,压缩格式和引擎类型必须设置为COMPRESSION_FORMAT_LZNT1。数据解压缩缓冲区的初始大小为4096字节,在成功解压数据之后,便获取实际的解压数据大小。此时需要将实际解压数据大小和数据解压缓冲区大小进行比较,如果数据解压缓冲区太小,则需要释放原来的缓冲区,重新按照实际解压数据的大小来申请一个新的数据解压缓冲区,并且重新解压缩数据。这样,才能获取所有的解压数据。

那么,使用RtlDecompressBuffer函数压缩数据的具体实现代码如下所示。

    // 数据解压缩BOOL UncompressData(BYTE *pCompressData, DWORD dwCompressDataLength, BYTE **ppUncompressData, DWORD *pdwUncompressDataLength){BOOL bRet = FALSE;HMODULE hModule = NULL;typedef_RtlDecompressBuffer RtlDecompressBuffer = NULL;BYTE *pUncompressData = NULL;DWORD dwUncompressDataLength = 4096;DWORD dwFinalUncompressSize = 0;do{// 加载 ntdll.dll hModule = ::LoadLibrary("ntdll.dll");if (NULL == hModule){ShowError("LoadLibrary");break;}// 获取 RtlDecompressBuffer 函数地址RtlDecompressBuffer = (typedef_RtlDecompressBuffer)::GetProcAddress(hModule, "RtlDecompressBuffer");if (NULL == RtlDecompressBuffer){ShowError("GetProcAddress");break;}while (TRUE){// 申请动态内存pUncompressData = new BYTE[dwUncompressDataLength];if (NULL == pUncompressData){ShowError("new");break;}::RtlZeroMemory(pUncompressData, dwUncompressDataLength);// 调用RtlCompressBuffer压缩数据RtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, pUncompressData, dwUncompressDataLength, pCompressData, dwCompressDataLength, &dwFinalUncompressSize);if (dwUncompressDataLength < dwFinalUncompressSize){// 释放内存if (pUncompressData){delete[]pUncompressData;pUncompressData = NULL;}dwUncompressDataLength = dwFinalUncompressSize;}else{break;}}// 返回*ppUncompressData = pUncompressData;*pdwUncompressDataLength = dwFinalUncompressSize;bRet = TRUE;} while (FALSE);// 释放if (hModule){::FreeLibrary(hModule);}return bRet;}

测试

直接运行上述程序,对“DDDDDDDDDDGGGGGGGGGGGG”字符串进行压缩得到压缩数据,再对压缩数据进行解压缩得到解压数据。得到的压缩数据和解压数据如下图:

利用 API 实现数据压缩和解压缩相关推荐

  1. ZLib的数据压缩和解压缩

    Delphi的开发者可以使用ZLib单元中定义的TCompressionStream进行数据压缩,使用TDecompressionStream解压缩ZLib压缩后的数据.它们的定义如下: TCusto ...

  2. 利用WinRar压缩和解压缩文件

    今天的rar shell只是一个简单应用,rar.exe和winrar.exe语法都是一样的. 对rar而言,用rar.exe最好,不需要判断winrar在哪里,而且非常小,因为没有界面,所有压缩选项 ...

  3. C# 利用ICSharpCode.SharpZipLib.dll 实现压缩和解压缩文件

    我们 开发时经常会遇到需要压缩文件的需求,利用C#的开源组件ICSharpCode.SharpZipLib, 就可以很容易的实现压缩和解压缩功能. 压缩文件: /// <summary> ...

  4. 在C#中利用SharpZipLib进行文件的压缩和解压缩

    我在做项目的时候需要将文件进行压缩和解压缩,于是就从http://www.icsharpcode.net下载了关于压缩和解压缩的源码,但是下载下来后,面对这么多的代码,一时不知如何下手.只好耐下心来, ...

  5. .Net 5中对于http请求的压缩和解压缩(GZip,Brotli)

    背景:(1)经常会有一些接口返回数据大,导致请求缓慢 (2)在后台请求一些第三方API时,需要解压缩响应数据,再进行处理 解决:可以通过对http请求进行压缩和解压来满足场景需求 1.先了解一下几种不 ...

  6. Java 的zip压缩和解压缩

    Java 的zip压缩和解压缩 好久没有来这写东西了,今天中秋节,有个东西想拿出来分享,一来是工作中遇到的问题,一来是和csdn问候一下,下面就分享一个Java中的zip压缩技术,代码实现比较简单,代 ...

  7. java putnextentry_Java对zip格式压缩和解压缩

    Java对zip格式压缩和解压缩 通过使用java的相关类可以实现对文件或文件夹的压缩,以及对压缩文件的解压. 1.1 ZIP和GZIP的区别 gzip是一种文件压缩工具(或该压缩工具产生的压缩文件格 ...

  8. EduCoder Linux之文件打包和解压缩

    本实训主要讲解Linux中对文件/目录压缩和解压缩操作. 随着多媒体.视频图象.文档映象等技术的出现,数据压缩成了一个重要研究点.数据压缩基本上是挤压数据使得它占用更少的磁盘存储空间和更短的传输时间. ...

  9. 使用GZipStream实现压缩和解压缩

    概述 之前做项目,涉及到存入到数据库或者http传输的数据量比较大,这个时候,就需要考虑在存入数据库或者发送传输之前,将数据压缩下,当从数据库中取出时,再解压还原数据.特地找了下发现有GZipStre ...

最新文章

  1. JS函数重载解决方案
  2. 基于概率统计分析的应用流特征分析
  3. 2.2_ 4_ FCFS、SJF、 HRRN调度算法
  4. 3-3:类与对象中篇——默认成员函数之构造函数和析构函数
  5. 将oracle优化器改为CBO,【DB.Oracle】Oracle 优化器 (RBO, CBO)
  6. android定时截取屏幕内容,Android 截取手机屏幕两种实现方案解析
  7. delphi mysql 加密_Delphi纯代码连SQLite数据库,同时支持数据库的加密解密
  8. Python count() 方法
  9. 工业互联网的数据集成
  10. 西门子S7-1200PLC3轴伺服控制程序 触摸屏是西门子Tp900
  11. 你可能不需要担心,AI对你的工作造成威胁:万字长文解读科技革命与人类发展
  12. PBX220评测报告
  13. 2022-2028年中国小麦组织蛋白行业市场发展潜力及投资前景分析报告
  14. C/C++test白盒测试的落地实践
  15. 产学研合作生态硬核来袭,共探数据库技术发展与应用
  16. Android反编译工具使用方法
  17. idea中maven执行install报错_maveninstall跳过测试
  18. Javaweb微专业第二十讲-----发送邮件(预告)
  19. python集合怎么表示_Python 集合(Set)、字典(Dictionary)
  20. ICML话题:机器学习近年来之怪现状

热门文章

  1. 部署KVM虚拟化平台
  2. php 记录用户积分,数据库创建 · CLTPHP用户签到积分功能,仿layui签到积分功能 · 看云...
  3. 元气骑士机器人修好后怎么用_元气骑士机器人攻略 机器人特性与使用技巧
  4. 计算机专硕学哪些专业,计算机考研学哪个专业
  5. jquery获取所有的兄弟元素
  6. matlab编写正弦波mif,使用MATLAB生成正弦波的MIF文件的问题
  7. 更少的图片标注工作,更棒的分类效果。肺结节诊断论文笔记。
  8. 【WZOI】 撕票 (连我的大神同桌都不会的题)
  9. 苹果研发团队钟爱手指陀螺?
  10. opencv3/C++图像边缘提取canny算子与Sobel算子实现opencv(VS2019 C++)