Perl 只读取特定的 gz 文件行
Perl reading only specific gz file lines
我正在尝试制作一个解析脚本来解析一个巨大的文本文件(超过 200 万行),该文件是 gunzip 压缩的。我只想解析文本文件中的一系列行。到目前为止,我已经使用 zgrep -n 找到提到字符串的两行,我知道这些字符串将开始和结束我感兴趣的文件部分。
在我的测试用例文件中,我只对读取第 123080 行到 139361 行感兴趣。我发现 Tie::File 可以使用数组对象 it returns 访问文件行,但不幸的是不适用于我正在使用的枪压缩文件。
是否有类似下面的压缩文件?
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...
}
Tie::File
对于大文件来说不是个好主意,因为它需要一次将整个文件存储在内存中。对于压缩文件,这也是一个不切实际的想法,如果不是不可能的话。相反,您将希望对数据的输入流进行操作。如果你要修改数据,输出流到数据的新副本。 Perl 通过 PerlIO::gzip
层对 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;
使用核心模块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 处理大文件时变得非常慢并且占用内存。
您写道:“在我的测试用例文件中,我只对读取第 123080 到 139361 行感兴趣”。
这也可以在 shell 中完成:
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 中的 zcat
、tail
和 head
将成为三个进程,而 perl 是第四个。所有四个都可能获得一个单独的 cpu 核心。您可能想用不同的行号测试速度。
我正在尝试制作一个解析脚本来解析一个巨大的文本文件(超过 200 万行),该文件是 gunzip 压缩的。我只想解析文本文件中的一系列行。到目前为止,我已经使用 zgrep -n 找到提到字符串的两行,我知道这些字符串将开始和结束我感兴趣的文件部分。
在我的测试用例文件中,我只对读取第 123080 行到 139361 行感兴趣。我发现 Tie::File 可以使用数组对象 it returns 访问文件行,但不幸的是不适用于我正在使用的枪压缩文件。
是否有类似下面的压缩文件?
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...
}
Tie::File
对于大文件来说不是个好主意,因为它需要一次将整个文件存储在内存中。对于压缩文件,这也是一个不切实际的想法,如果不是不可能的话。相反,您将希望对数据的输入流进行操作。如果你要修改数据,输出流到数据的新副本。 Perl 通过 PerlIO::gzip
层对 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;
使用核心模块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 处理大文件时变得非常慢并且占用内存。
您写道:“在我的测试用例文件中,我只对读取第 123080 到 139361 行感兴趣”。
这也可以在 shell 中完成:
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 中的 zcat
、tail
和 head
将成为三个进程,而 perl 是第四个。所有四个都可能获得一个单独的 cpu 核心。您可能想用不同的行号测试速度。