你能从Perl中的.tar.bz2档案流式传输每个文件的文件吗?

时间:2016-11-03 09:07:31

标签: perl tar compression bzip2

我们有很多压缩数据,实际上是包含XML文件的目录及其子目录的压缩录音存档; e.g。

omega/    
- alpha/
  - a/
    - file1.xml
    - file2.xml
    - file3.xml
  - b/
    - file1.xml
    - file2.xml
    - file3.xml
  - c/
    - ...
- beta/
  - a/
    - file1.xml
    - file2.xml
    - file3.xml
  - b/
    - ...
  - c/
    - ...
- gamma/
  - a/
    - ...
  - b/
    - ...
  - c/
    - ...

结果将是omega.tar.bz2等文件,这些文件的大小可达数百GB。

即使我们知道这是 archive 文件类型,但仍然可以在需要时使用其内容。因此,我想知道是否可以以流方式从Perl中读取这些文件,即无需首先解压缩和解压缩磁盘上的所有内容,或者无需加载整个 *.tar.bz2归档到内存中。

我知道使用IO::Uncompress你可以使用Bunzip2,但据我所知和测试,这会将整个文件读入内存,这对于我们的大文件是不可能的。 Bunzipping下面的示例代码(不包括TAR)。

use strict;
use warnings;
use IO::Uncompress::Bunzip2 qw(bunzip2 $Bunzip2Error) ;

my $filename = '/path/to/file/file1.xml.bz2';
open(my $fh, '<', $filename)
  or die "Could not open file '$filename' $!";

my $buffer ;
bunzip2 $filename => \$buffer
  or die "bunzip2 failed: $Bunzip2Error\n";

print STDOUT "$buffer\n";

考虑到TAR,还有Archive::Extract模块允许将.tar.bz2文件(类型tbz)读入Extract Object,但这又会将整个文件读入内存,这是我们的巨大文件无法实现的。

由于我自己对该主题的研究,我认为不可能以流式方式读取BZIP2的TAR,即每行的行数。我没有压缩经验,所以也许有一种方法可以在给定大量数据块的情况下重建文件行。

Tl; dr:你可以从BZIP2压缩的TAR档案中流式传输文件内容(每行或类似行)吗?

2 个答案:

答案 0 :(得分:2)

Compress::Raw::Bzip2允许你按块解压缩bzip2输入块,即在流中解压缩。但是因为.tar.bz2首先是一个tar文件然后用bzip2压缩,你需要首先将所有数据解压缩到tar文件中的文件位置,然后才能访问你想要的数据,即没有办法寻求文件而不解压缩到此文件的所有内容。如果您对此很好,您可以使用Archive::Tar::Stream,即将来自bzip2解码器的输入提供给流式Tar解析器。我自己从未使用它,但看起来它是为这种用例而开发的。

如果您可以选择更改输入文件的格式,我建议使用将压缩文件存储在存档中的格式(如ZIP),而不是压缩完整存档(即.tar.bz2)。这样,您可以轻松地搜索特定的压缩文件并仅解压缩此文件,而不是解压缩到此文件的所有内容。

答案 1 :(得分:0)

所有IO :: Compress和IO :: Uncompress模块​​都支持流式传输,包括IO :: Uncompress :: Bunzip2。您展示的示例代码(见下文)使用便捷方法(bunzip2)用于常见用例,您希望从文件中读取所有压缩数据并一次性将其解压缩到缓冲区。

my $buffer ;
bunzip2 $filename => \$buffer
  or die "bunzip2 failed: $Bunzip2Error\n";

以下是流式Bunzip2用例的用法

my $bz = IO::Uncompress::Bunzip2->new($filename);

# $bz is a regular Perl filehandle, so can read it a line at a time
while (<$bz>)
{
    ....
}

# or a bock at a time
read($bz, $buffer, 1024);

close $gz;

如果你能找到一个接受perl文件句柄并且本身就是流式传输的tar模块,你可以给它一个IO :: Uncompress :: Bubzip2对象。

另一种选择是让“真正的”tar二进制文件为您处理。更新版本的gnu tar会自动检测压缩,你可以让tar写入stdout。所以你可以打开tar命令的文件句柄,就像这样

open my $data, "tar -Of $file.tar.bz2 |";

while (<$data>)
{
    ....
}