我希望将分布在大量子目录中的大量数据压缩到存档中。我不能简单地使用内置的 tar 函数,因为我需要我的 Perl 脚本在 Windows 和 Linux 环境中工作。我找到了该Archive::Tar
模块,但他们的文档给出了警告:
请注意,此方法 [
create_archive()
] 不会on the fly
按原样写入;在写出存档之前,它仍然会将所有文件读入内存。如果这是一个问题,请参阅下面的常见问题解答。
由于我的数据量很大,我想“即时”写。但我在常见问题解答中找不到有关写入文件的有用信息。他们建议使用迭代器iter()
:
返回一个迭代器函数,该函数读取 tar 文件而不将其全部加载到内存中。每次调用该函数时,它都会返回 tarball 中的下一个文件。
my $next = Archive::Tar->iter( "example.tar.gz", 1, {filter => qr/\.pm$/} ); while( my $f = $next->() ) { print $f->name, "\n"; $f->extract or warn "Extraction failed"; # .... }
但这仅讨论文件的读取,而不是压缩存档的写入。所以我的问题是,如何获取一个目录并以内存友好的方式$dir
将其递归地添加到使用 bzip2 压缩的存档中,即无需先将整个树加载到内存中?archive.tar.bz2
Archive::Tar::Streamed
我尝试使用and使用评论中的建议构建自己的脚本IO::Compress::Bzip2
,但无济于事。
use strict;
use warnings;
use Archive::Tar::Streamed;
use File::Spec qw(catfile);
use IO::Compress::Bzip2 qw(bzip2 $Bzip2Error);
my ($in_d, $out_tar, $out_bz2) = @ARGV;
open(my $out_fh,'>', $out_tar) or die "Couldn't create archive";
binmode $out_fh;
my $tar = Archive::Tar::Streamed->new($out_fh);
opendir(my $in_dh, $in_d) or die "Could not opendir '$in_d': $!";
while (my $in_f = readdir $in_dh) {
next unless ($in_f =~ /\.xml$/);
print STDOUT "Processing $in_f\r";
$in_f = File::Spec->catfile($in_d, $in_f);
$tar->add($in_f);
}
print STDOUT "\nBzip'ing $out_tar\r";
bzip2 $out_tar => $out_bz2
or die "Bzip2 failed: $Bzip2Error\n";
很快,我的系统内存不足。我当前的系统中有 32GB 可用空间,但它几乎立即被淹没。我尝试添加到存档的目录中的某些文件超过 32GB。
所以我想知道即使在Streamed
课堂上每个文件都必须在添加到存档之前完全在内存中读取?我假设文件本身将在缓冲区中流式传输到存档,但也许只是不是首先将所有文件保存在内存中,而是Streamed
允许完全只需要内存中的一个文件,然后将其逐个添加到存档中?