miniz - 简易zlib压缩
作者:沈园园
一、概述
FastLZ 和 miniz 都是流行的压缩库,但它们在设计目标、压缩算法、性能特点等方面有显著区别,适用于不同的应用场景。
FastLZ 是一款高效且小巧的开源压缩库,主要用于实现基于 LZ77 算法的字节对齐数据压缩。
LZ77(Lempel-Ziv 1977)是数据压缩领域的一种基础方法,其核心思想是通过查找源数据中的重复模式来减少存储空间。
适用于压缩文本/段落序列、原始像素数据序列或具有大量重复的任何其他数据块。但是不打算用于图像、视频和其他通常已经以最佳压缩形式存在的格式的数据。
FastLZ 的重点是非常快速的压缩和解压缩。
miniz是一个单一文件的小型压缩库,它是zlib的一个替代品,专门为需要轻量级压缩解决方案的项目设计,它被设计成可以轻松地集成到项目中,并且具有最小的依赖性。
miniz的主要特点包括:
- 支持zlib兼容的压缩和解压缩。
- 单个源文件实现,易于集成。
- 小的内存占用,适合资源受限的环境。
- 支持流式压缩和解压缩。
压缩比, miniz的压缩比要好于fastlz
总结:FastLZ 是 "速度优先"的轻量选择,miniz 是 "兼容zlib和压缩率优先" 的通用选择。
二、核心示例
1、核心示例是指:使用本库文件提供的核心API,开发的基础业务逻辑的演示代码;
2、核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;
3、更加完整和详细的demo,请参考 LuatOS仓库 中各个产品目录下的demo/miniz
-- 准备好数据
local bigdata = "123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw"
-- 压缩之, 压缩得到的数据是zlib兼容的,其他语言可通过zlib相关的库进行解压
local cdata = miniz.compress(bigdata)
-- lua 的 字符串相当于有长度的char[],可存放包括0x00的一切数据
if cdata then
-- 检查压缩前后的数据大小
log.info("miniz", "before", #bigdata, "after", #cdata)
log.info("miniz", "cdata as hex", cdata:toHex())
-- 解压, 得到原文
local udata = miniz.uncompress(cdata)
log.info("miniz", "udata", udata)
end
三、常量详解
核心库常量,顾名思义是由合宙 LuatOS 内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;
每个常量对应的常量取值仅做日志打印时查询使用,不要将这个常量取值用做具体的业务逻辑判断,因为LuatOS内核固件可能会变更每个常量对应的常量取值;
如果用做具体的业务逻辑判断,一旦常量取值发生改变,业务逻辑就会出错;
3.1 miniz.WRITE_ZLIB_HEADER
常量含义:压缩参数,是否写入zlib头部数据,compress函数的默认值;
数据类型:number;
常量取值:0x01000;
示例代码:miniz.compress("123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw", miniz.WRITE_ZLIB_HEADER)
3.2 miniz.COMPUTE_ADLER32
常量含义:压缩/解压参数,是否计算/校验adler-32;
数据类型:number;
常量取值:0x02000;
示例代码:miniz.compress("123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw", miniz.COMPUTE_ADLER32)
3.3 miniz.GREEDY_PARSING_FLAG
常量含义:压缩参数,是否快速greedy处理, 默认使用较慢的处理模式;
数据类型:number;
常量取值:0x04000;
示例代码:miniz.compress("123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw", miniz.GREEDY_PARSING_FLAG)
3.4 miniz.NONDETERMINISTIC_PARSING_FLAG
常量含义:压缩参数,是否快速初始化压缩器;
数据类型:number;
常量取值:0x04000;
示例代码:miniz.compress("123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw", miniz.NONDETERMINISTIC_PARSING_FLAG)
3.5 miniz.RLE_MATCHES
常量含义:压缩参数, 仅扫描RLE;
数据类型:number;
常量取值:0x10000;
示例代码:miniz.compress("123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw", miniz.RLE_MATCHES)
3.6 miniz.FILTER_MATCHES
常量含义:压缩参数,过滤少于5次的字符;
数据类型:number;
常量取值:0x20000;
示例代码:miniz.compress("123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw", miniz.FILTER_MATCHES)
3.7 miniz.FORCE_ALL_STATIC_BLOCKS
常量含义:压缩参数,是否禁用优化过的Huffman表;
数据类型:number;
常量取值:0x40000;
示例代码:miniz.compress("123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw", miniz.FORCE_ALL_STATIC_BLOCKS)
3.8 miniz.FORCE_ALL_RAW_BLOCKS
常量含义:压缩参数,是否只要raw块;
数据类型:number;
常量取值:0x80000;
示例代码:miniz.compress("123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw", miniz.FORCE_ALL_RAW_BLOCKS)
3.9 miniz.PARSE_ZLIB_HEADER
常量含义:解压参数,是否处理zlib头部,uncompress函数的默认值;
数据类型:number;
常量取值:1;
示例代码:{
local cdata = miniz.compress("123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw")
local udata = miniz.uncompress(cdata, miniz.PARSE_ZLIB_HEADER)
}
3.10 miniz.HAS_MORE_INPUT
常量含义:解压参数,是否还有更多数据,仅流式解压可用,暂不支持;
数据类型:number;
常量取值:2;
示例代码:暂无;
3.11 miniz.USING_NON_WRAPPING_OUTPUT_BUF
常量含义:解压参数,解压区间是否够全部数据,仅流式解压可用,暂不支持;
数据类型:number;
常量取值:4;
示例代码:暂无;
3.12 miniz.COMPUTE_ADLER32
常量含义:解压参数,是否强制校验adler-32;
数据类型:number;
常量取值:8;
示例代码:{
local cdata = miniz.compress("123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw", miniz.COMPUTE_ADLER32)
local udata = miniz.uncompress(cdata, miniz.COMPUTE_ADLER32)
}
四、函数详解
4.1 miniz.compress(data, flags)
快速压缩,需要165KB的系统内存和32KB的LuaVM内存
参数
data
参数含义:待压缩的数据;
数据类型:string;
取值范围:压缩后的数据不能大于32KB
{
在使用 miniz 库进行压缩前,无法精确预测压缩后的大小(因为压缩率取决于数据的冗余度、重复模式等特性)
可根据数据类型做经验性预估(近似判断):
文本类数据(如 JSON、XML、日志):压缩率通常在 30%~70%,可假设压缩后大小约为原大小的 50%。若原数据 > 64KB(32KB / 50%),则压缩后可能超过 32KB。
二进制数据(如图片、已压缩文件):压缩率低(甚至可能膨胀),若原数据 > 30KB,压缩后可能超过 32KB。
空数据或极小数据:压缩后可能因 miniz 的头部信息(约 20 字节)略大于原大小,但肯定 <32KB。
};
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:"123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw";
flags
参数含义:压缩参数
数据类型:number;
取值范围:参考第三章常量详解;
是否必选:非必须传入此参数,默认是 miniz.WRITE_ZLIB_HEADER , 即写入zlib头部;
注意事项:暂无;
参数示例:miniz.WRITE_ZLIB_HEADER;
返回值 local cdata = miniz.compress(data, flags)
cdata
含义说明:若压缩成功,返回数据字符串, 否则返回nil
数据类型:string或者nil;
取值范围:小于等于32KB;
注意事项:暂无;
返回示例:可能会含有不可见字符,通过cdata:toHex()格式打印;
示例
local bigdata = io.readFile("/luadb/test.txt") or
"123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw 123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw"
local cdata = miniz.compress(bigdata)
if cdata then
log.info("miniz", "before", #bigdata, "after", #cdata)
--before 129 after 102 (对应例子中129字节数据)
--before 14525 after 9554 (从文件中读取14525字节数据)
--before 30180 after 19832 (从文件中读取30180字节数据)
log.info("miniz", "cdata as hex", cdata:toHex())
--[[
78010540D10D8430085DE556D0FAA1E934187D3E6A23564258FF32CDA5C1742CEC37DAFE881FDAC11869951027DE6D6459F941D4BC121A2617D1434EF
5FC4D7369301D0BFB8DB63FE2877630465A25C489771B59567E1035AF8486C945F490533DFF817D31E5 204]]
end
4.2 miniz.uncompress(data, flags)
快速解压,需要32KB的LuaVM内存
参数
data
参数含义:待解压的数据
数据类型:string;
取值范围:长度小于32KB的任意字符串数据;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:{
--可以先把数据压缩,然后解压压缩后的数据看是否相同;
local bigdata = "123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw 123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw"
local cdata = miniz.compress(bigdata)
local udata = miniz.uncompress(cdata)
}
flags
参数含义:解压缩参数
数据类型:number;
取值范围:参考第三章常量详解;
是否必选:非必须传入此参数,默认是 miniz.PARSE_ZLIB_HEADER , 即写入zlib头部;
注意事项:暂无;
参数示例:miniz.PARSE_ZLIB_HEADER;
返回值 local udata = miniz.uncompress(data, flags)
udata
含义说明:若解压成功,返回数据字符串, 否则返回nil
数据类型:string或者nil;
取值范围:无特别限制;
注意事项:暂无;
返回示例:"123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw";
示例
local bigdata = "123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw 123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw"
local cdata = miniz.compress(bigdata)
if cdata then
log.info("miniz", "before", #bigdata, "after", #cdata) --before 129 after 102
log.info("miniz", "cdata as hex", cdata:toHex())
--[[
78010540D10D8430085DE556D0FAA1E934187D3E6A23564258FF32CDA5C1742CEC37DAFE881FDAC11869951027DE6D6459F941D4BC121A2617D1434EF5FC4D7369301D0B
FB8DB63FE2877630465A25C489771B59567E1035AF8486C945F490533DFF817D31E5 204]]
local udata = miniz.uncompress(cdata)
log.info("miniz", "udata", udata)
--123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw 123jfoiq4hlkfjbnasdilfhuqwo;hfashfp9qw38hrfaios;hfiuoaghfluaeisw
end
五、产品支持说明
支持LuatOS开发的所有产品都支持miniz核心库。