如何不解压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
相关产品推荐
相关产品推荐

