多数のサブディレクトリにまたがる大量のデータをアーカイブに圧縮しようとしています。Perl スクリプトを Windows および Linux 環境で動作させる必要があるため、組み込みの tar 関数を単純に使用することはできません。Archive::Tar
モジュールは見つかりましたが、そのドキュメントには警告が表示されます。
このメソッド [
create_archive()
] はそのままでは記述されないことに注意してくださいon the fly
。アーカイブを書き出す前に、すべてのファイルをメモリに読み込みます。これが問題である場合は、以下の FAQ を参照してください。
データのサイズが大きいため、「その場で」書きたいと思います。しかし、ファイルの書き込みに関する FAQ には有用な情報が見つかりません。彼らは iterator を使うことを提案します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"; # .... }
ただし、これはファイルの読み取りについてのみ説明しており、圧縮されたアーカイブの書き込みについては説明していません。だから私の質問は、ディレクトリを取得して、メモリに優しい方法で、つまり最初にツリー全体をメモリにロードせずに、bzip2 圧縮を使用し$dir
てアーカイブに再帰的に追加するにはどうすればよいかということです。archive.tar.bz2
Archive::Tar::Streamed
と を使用してコメントの提案を使用して独自のスクリプトを作成しようとしました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
1つのファイルのみを完全に必要とし、それをアーカイブに1つずつ追加するだけですか?