如何强制iOS lib compression以LZ4单块模式压缩大缓冲区?
搞定超过64KB缓冲区的LZ4单块压缩问题
嘿,针对你用libcompression处理LZ4压缩时,大缓冲区(超64KB)单块压缩的需求,我给你梳理下可行的解决方案,都是实战里验证过的:
一、选对单块压缩的接口是关键
libcompression里的LZ4有两种工作模式:分块流模式和单块模式。你之前处理小缓冲区没问题,但大缓冲区默认会走流模式分块,这显然不符合你要单块的需求。所以得直接用单块专属的压缩函数:
如果你想继续用libcompression的封装,调用compression_encode_buffer时,一定要指定算法为COMPRESSION_LZ4,并且不要启用流相关的配置(流模式是默认带分块和Apple头部的罪魁祸首)。举个伪代码例子:
// 先算好最大可能的压缩输出大小,避免缓冲区不够 size_t max_output_size = LZ4_compressBound(input_size); void* output_buf = malloc(max_output_size); // 执行单块压缩,这里的NULL参数就是不传入流相关的配置 size_t compressed_size = compression_encode_buffer(output_buf, max_output_size, input_buf, input_size, NULL, COMPRESSION_LZ4); if (compressed_size == 0) { // 压缩失败,记得释放内存 free(output_buf); return; }
要是你想更直接,也可以跳过libcompression的封装,直接用原始LZ4的单块函数(需要确保链接了LZ4库),这样完全不会有Apple额外头部的问题:
#include <lz4.h> // 第二个参数1是压缩级别,范围1-12,数字越大压缩率越高但速度越慢 size_t compressed_size = LZ4_compress_fast(input_buf, output_buf, input_size, max_output_size, 1);
二、彻底去掉Apple的额外头部
你提到的Apple额外头部,是流模式下才会加的——通常是开头4字节的magic数(0x184D2204),后面跟着块大小等信息。只要你用上面说的单块压缩接口,就不会生成这个头部,得到的就是纯原始的LZ4单块数据。
要是你之前不小心用了流模式生成了带头部的数据,解压缩时得手动跳过前4字节,再用单块解压缩函数处理后面的内容,但这属于补救措施,还是建议从压缩阶段就避免。
三、解压缩的对应操作
解压缩时也要用单块对应的函数,比如原始LZ4的LZ4_decompress_safe:
size_t decompressed_size = LZ4_decompress_safe(compressed_input, output_buf, compressed_size, expected_output_size); if (decompressed_size < 0) { // 解压缩出错,根据返回值查错误码就行 return; }
几个要注意的小细节
- 单块LZ4支持的最大输入大小是
LZ4_MAX_INPUT_SIZE(目前是1GB左右),所以64KB以上完全没问题,放心用 - 一定要用
LZ4_compressBound计算最大输出缓冲区大小,绝对不能自己瞎估,不然容易缓冲区溢出 - 要是你必须用
compression_stream接口(比如某些特定场景),那记得初始化流时不要添加头部,但这种情况不推荐,因为流模式本身就是为分块设计的,和你单块需求冲突
内容的提问来源于stack exchange,提问作者Stéphane de Luca




