You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何强制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

火山引擎 最新活动