You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何不解压gzipped tar归档文件并读取为Vec<u8>?

问题原因与解决方案

你的代码核心问题是压缩归档没有完全写入磁盘:tar::Builder::finish()仅完成了tar归档的写入,但底层的GzEncoder还未完成压缩收尾(比如写入gzip的CRC校验、文件长度等尾部信息),此时直接读取文件,得到的是不完整的内容。

修复后的代码

use std::fs::File;
use flate2::write::GzEncoder;
use flate2::Compression;
use tar::Builder;

fn main() {
    // 1. 创建目标文件
    let file = File::create("example.tar.gz").unwrap();
    // 2. 初始化Gzip压缩编码器
    let mut encoder = GzEncoder::new(file, Compression::default());
    // 3. 创建Tar归档构建器
    let mut archive = Builder::new(&mut encoder);
    // 4. 将目标目录添加到Tar归档
    archive.append_dir_all("example_dir", "path/to/example_dir").unwrap();
    
    // 5. 完成Tar归档内容写入(将Tar数据传递给Gzip编码器)
    archive.finish().unwrap();
    // 6. 完成Gzip压缩收尾(写入gzip格式的尾部校验信息)
    encoder.finish().unwrap();

    // 此时读取文件即可获取完整字节
    let example_bytes = std::fs::read("example.tar.gz").unwrap();
    dbg!(example_bytes.len());
    
    // 重写的文件不会损坏
    std::fs::write("rewritten.tar.gz", example_bytes).unwrap();
}

关键说明

  • archive.finish()仅完成tar格式的内容写入,GzEncoder此时仍在缓冲压缩数据,必须调用encoder.finish()触发压缩收尾,确保gzip的尾部校验块写入磁盘,文件才是完整可用的。
  • 之前用std::fs::read只读到10字节,是因为GzEncoder未完成写入,仅写入了gzip头部,其余数据还在内存缓冲中。
  • 使用BufReader读取到的文件少392字节,是因为缺少gzip尾部的校验块,导致文件损坏。

读取文件的简化方式

只要文件被正确写入,直接用std::fs::read就可以完整读取所有字节,不需要额外使用BufReader(除非处理超大文件需要流式读取)。如果是超大文件,流式读取的正确写法如下:

use std::fs::File;
use std::io::BufReader;

fn main() {
    let file = File::open("example.tar.gz").unwrap();
    let mut reader = BufReader::new(file);
    let mut bytes = Vec::new();
    
    // 打开文件时指针默认在开头,无需手动rewind
    reader.read_to_end(&mut bytes).unwrap();
    
    std::fs::write("rewritten.tar.gz", bytes).unwrap();
}

内容的提问来源于stack exchange,提问作者Ali Somay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 05:55:15