Perl читает только определенные строки файла gz
Я пытаюсь создать скрипт синтаксического анализа, который анализирует огромный текстовый файл (более 2 миллионов строк), сжатый с помощью gunzip. Я только хочу проанализировать диапазон строк в текстовом файле. До сих пор я использовал zgrep -n, чтобы найти две строки, в которых упоминается строка, которая, как я знаю, будет начинать и заканчивать интересующий меня раздел файла.
В моем файле тестового примера меня интересует только чтение в строках с 123080 по 139361. Я нашел Tie::File для доступа к строкам файла с помощью возвращаемого объекта массива, но, к сожалению, это не сработает для файла zip-пистолета. Я работаю с.
Есть ли что-то вроде следующего для заархивированного файла?
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 ответа
Используйте http://p3rl.org/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 становится очень медленным и требует много памяти при обработке больших файлов.
Tie::File
плохая идея для больших файлов, так как нужно хранить весь файл в памяти сразу. Это также непрактичная, если не невозможная идея для сжатых файлов. Вместо этого вы захотите работать с потоком ввода ваших данных. И если вы собираетесь изменить данные, выходной поток в новую копию данных. Perl имеет довольно хорошую поддержку сжатия gzip через PerlIO::gzip' layer, but you could also pipe data through one or two
гзип` процессы.
# 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, как и любые другие файловые дескрипторы.
# 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;
Вы пишете: "В моем файле теста я интересуюсь только чтением в строках с 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, так как zcat
, tail
а также head
внутри qx станет три процесса, а perl - четвертый. И все четыре могут получить отдельное ядро процессора самостоятельно. Возможно, вы захотите проверить скорость с разными номерами строк.