如何通过xz API提取xz压缩文件的未解压大小?
解决方案
你可以使用Linux系统默认预装的标准liblzma(xz官方开发的C库)提供的索引解析API实现需求,该方案适配所有xz格式支持的压缩算法,不需要自己手动解析特定算法的流元数据。
核心实现逻辑
- xz格式的尾部存储了全文件的索引结构,记录了所有数据块的未压缩长度、压缩长度等元信息,
liblzma提供了现成的API直接读取该索引的统计值 - 核心调用为
lzma_index_uncompressed_size(),传入解析完成的索引对象即可返回uint64_t类型的总未压缩文件大小
依赖和编译说明
- 开发依赖安装(Debian/Ubuntu为例):
apt install liblzma-dev - 编译时链接参数:
gcc your_code.c -o your_binary -llzma
简化示例代码
#include <lzma.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> uint64_t get_xz_uncompressed_size(FILE *fp) { // 读取xz文件尾部12字节的标准footer fseek(fp, -LZMA_STREAM_HEADER_SIZE, SEEK_END); uint8_t footer_buf[LZMA_STREAM_HEADER_SIZE]; if (fread(footer_buf, 1, LZMA_STREAM_HEADER_SIZE, fp) != LZMA_STREAM_HEADER_SIZE) { return UINT64_MAX; } lzma_stream_flags footer_flags; if (lzma_stream_footer_decode(&footer_flags, footer_buf) != LZMA_OK) { return UINT64_MAX; // 非合法xz格式 } // 读取索引区块数据 fseek(fp, -(LZMA_STREAM_HEADER_SIZE + footer_flags.backward_size), SEEK_END); uint8_t *index_buf = malloc(footer_flags.backward_size); if (index_buf == NULL || fread(index_buf, 1, footer_flags.backward_size, fp) != footer_flags.backward_size) { free(index_buf); return UINT64_MAX; } lzma_index *index = NULL; const lzma_allocator *allocator = NULL; size_t memlimit = UINT64_MAX; size_t in_pos = 0; lzma_ret ret = lzma_index_parse(allocator, &index, index_buf, footer_flags.backward_size, &in_pos, memlimit); free(index_buf); if (ret != LZMA_OK) { return UINT64_MAX; } uint64_t uncomp_size = lzma_index_uncompressed_size(index); lzma_index_end(index, allocator); return uncomp_size; }
注意事项
- 该API仅对标准xz封装格式生效,如果你处理的是无封装的裸压缩流,才需要手动解析对应算法的头部元数据
- 如果返回值为
UINT64_MAX,说明该xz文件为流式生成,写入时未记录未压缩大小,无法预分配固定内存,需使用动态缓冲区处理 - 多流拼接的xz文件可通过
lzma_index_cat合并多个流的索引后再计算总大小,同样适配所有压缩算法
内容的提问来源于stack exchange,提问作者Dov
相关产品推荐
相关产品推荐

