Perl仅读取特定的gz文件行

时间:2018-12-06 00:35:02

标签: perl gz tie

我正在尝试创建一个解析脚本,该脚本解析经过gunzip压缩的巨大文本文件(超过200万行)。我只想解析文本文件中的一系列行。到目前为止,我已经使用zgrep -n查找提到我知道将在我感兴趣的文件部分的开头和结尾的字符串的两行。

在我的测试用例文件中,我只想读取第123080至139361行。我发现Tie :: File使用它返回的数组对象访问文件行,但不幸的是,这对枪支不起作用我正在使用的压缩文件。

枪击文件是否存在以下内容?

use Tie::File
tie @fileLinesArray, 'Tie::File', "hugeFile.txt.gz"
my $startLine = 123080;

my $endLine = 139361;    
my $lineCount = $startLine;
while ($lineCount <= $endLine){
    my $line = @fileLinesArray[$lineCount]
    blah blah...
}

3 个答案:

答案 0 :(得分:4)

使用IO::Uncompress::Gunzip这是一个核心模块:

use IO::Uncompress::Gunzip;

my $z = IO::Uncompress::Gunzip->new('file.gz');
$z->getline for 1 .. $start_line - 1;
for ($start_line .. $end_line) {
    my $line = $z->getline;
    ...
}

Tie::File在处理大文件时变得非常慢并且占用大量内存。

答案 1 :(得分:2)

Tie::File对于大文件不是一个好主意,因为它需要立即将整个文件存储在内存中。对于压缩文件来说,这也是一个不切实际的想法,即使不是不可能的想法。相反,您将需要对数据的输入流进行操作。而且,如果您要修改数据,则输出流到数据的新副本。 Perl通过PerlIO::gzip' layer, but you could also pipe data through one or two gzip`进程对gzip压缩提供了很好的支持。

# I/O stream initialization
use PerlIO::gzip;
open my $input, "<:gzip", "data.gz";
open my $output. ">:gzip", "data.new.gz";    # if $output is needed

# I/O stream initialization without PerlIO::gzip
open my $input, "gzip -d data.gz |";
open my $output, "| gzip -c > data.new.gz";

一旦设置了输入(和可选输出)流,就可以像使用其他文件句柄一样在它们上使用Perl的I / O工具。

# copy first $startLine lines unedited
while (<$input>) {
    print $output $_;
    last if $. >= $startLine;
}

while (my $line = <$input>) {
    # blah blah blah
    # manipulate $line
    print $output $line;
    last if $. >= $endLine;
}

print $output <$input>; # write remaining input to output stream
close $input;
close $output;

答案 2 :(得分:1)

您写道:“ 在我的测试用例文件中,我只想读取123080至139361行”。

这也可以在外壳中完成:

zcat file | tail -n +123080 | head -16282

或通过:

my $file = 'the_file.gz';
my($from,$to) = (123080,139361);
my @lines = qx( zcat $file | tail -n +$from | head -@{[-$from+$to+1]});

这可能比普通的单核纯perl解决方案要快,因为qx内的zcattailhead将变成三个进程,而perl则是第四个进程。这四个人可能会各自获得一个单独的cpu核心。您可能想用不同的行号测试速度。