rust – 如何在不使用大量RAM的情况下创建一个gzipped tar文件?

我正在尝试创建一个gzipped tar文件而不占用大量内存. Bash等同于我想要做的是:

tar -cf - -C $INPUT . | gzip -cv - > $OUTPUT

我正在使用tarflate2库,它们都说支持流媒体.我无法弄清楚如何将一个流送到另一个.我曾尝试查看Write实现者,但没有看到符合我需求的流类型.

我当前的实现具有所需的输出(即.tar.gz文件),但它占用了大量的RAM,尤其是当文件大小很大时.当输入大小很大时,创建的文件还会提供“tar:存档中的意外EOF”,但输入较小时可以正常使用.这告诉我,它不像Bash那样管道流.

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

// Create tar archive
let mut archive = Builder::new(Vec::new());
archive.append_dir_all("myfiles", "myfiles")?;

// Gzip tar archive and write to file
let compressed_file = File::create("backup.tar.gz")?;
let mut encoder = GzEncoder::new(compressed_file, Compression::Default);
encoder.write(&archive.into_inner()?)?;
encoder.finish()?;
最佳答案
要了解为什么使用RAM以及为什么tar报告大文件的错误,让我们了解您的代码究竟在做什么:

let mut archive = Builder::new(Vec::new());

查看Builder::new文档,我们已经可以看到主要问题:“创建一个新的归档构建器,其中底层对象是所有写入数据的目标”.由于您传递的是Vec(实现Write),因此所有tar压缩数据的目标都将写入向量.但是矢量存储在RAM中.

archive.append_dir_all("myfiles", "myfiles")?;

这一行已经将文件压缩到向量中,所以在这一行中,RAM填满了.

跳过几行:

encoder.write(&archive.into_inner()?)?;

在这里,您告诉编码器写下您刚填充的矢量.但是,重要的是要记住,Write::write()不能保证写入多少数据!它是较低级别的构建块,用于更高级别的功能,更可靠.您想要使用write_all()而不是将重复调用write()直到写入所有数据.因此,由于您只使用write(),因此只会写入部分数据.当您的数据非常少时,通常可以一次性写入,但是一旦您拥有更多数据,该错误就会变得明显.

那又怎么办呢?简单:Builder :: new()需要一些实现Write的东西并将其用作目标.但是你的tar编码器确实实现了Write.因此,这应该工作:

// Create Gzip file
let compressed_file = File::create("backup.tar.gz")?;
let mut encoder = GzEncoder::new(compressed_file, Compression::Default);

{
    // Create tar archive and compress files 
    let mut archive = Builder::new(&mut encoder);
    archive.append_dir_all("myfiles", "myfiles")?;
}

// Finish Gzip file
encoder.finish()?;

转载注明原文:rust – 如何在不使用大量RAM的情况下创建一个gzipped tar文件? - 代码日志