Как прочитать строки из конца файла в Perl?
Я работаю над скриптом Perl для чтения CSV-файла и выполнения некоторых вычислений. CSV-файл имеет только два столбца, что-то вроде ниже.
One Two
1.00 44.000
3.00 55.000
теперь этот файл CSV очень большой, может быть от 10 МБ до 2 ГБ.
В настоящее время я беру CSV-файл размером 700 МБ. Я попытался открыть этот файл в notepad, excel, но похоже, что никакое программное обеспечение не собирается его открывать.
Я хочу прочитать последние 1000 строк из CSV-файла и посмотреть значения. Как я могу это сделать? Я не могу откройте файл в блокноте или любой другой программе.
Если я пишу сценарий Perl, мне нужно обработать полный файл, чтобы перейти к концу файла, а затем прочитать последние 1000 строк.
есть ли лучший способ сделать это? Я новичок в Perl и любые предложения будут оценены.
Я искал сеть, и есть некоторые скрипты, такие как File::Tail, но я не знаю, что они будут работать на windows ?
11 ответов
на File:: ReadBackwards модуль позволяет читать файл в обратном порядке. Это позволяет легко получить последние N строк, Если вы не зависите от заказа. Если вы и необходимые данные достаточно малы (что должно быть в вашем случае), вы можете прочитать последние 1000 строк в массив, а затем reverse
его.
Это только касательно связано с вашим основным вопросом, но когда вы хотите проверить, такой ли модуль, как File:: Tail работает на вашей платформе, проверить результаты тестеры CPAN. Ссылки в верхней части страницы модуля в поиск CPAN привести
глядя на матрицу, вы видите, что действительно этот модуль имеет проблему в Windows на всех версиях Perl проверено:
Я написал быстрый обратный поиск файлов, используя следующий код на pure Perl:
#!/usr/bin/perl
use warnings;
use strict;
my ($file, $num_of_lines) = @ARGV;
my $count = 0;
my $filesize = -s $file; # filesize used to control reaching the start of file while reading it backward
my $offset = -2; # skip two last characters: \n and ^Z in the end of file
open F, $file or die "Can't read $file: $!\n";
while (abs($offset) < $filesize) {
my $line = "";
# we need to check the start of the file for seek in mode "2"
# as it continues to output data in revers order even when out of file range reached
while (abs($offset) < $filesize) {
seek F, $offset, 2; # because of negative $offset & "2" - it will seek backward
$offset -= 1; # move back the counter
my $char = getc F;
last if $char eq "\n"; # catch the whole line if reached
$line = $char . $line; # otherwise we have next character for current line
}
# got the next line!
print $line, "\n";
# exit the loop if we are done
$count++;
last if $count > $num_of_lines;
}
и запустите этот скрипт как:
$ get-x-lines-from-end.pl ./myhugefile.log 200
без хвоста решение Perl-only не является необоснованным.
один из способов-искать с конца файла, а затем читать строки из него. Если у вас недостаточно линий, ищите еще дальше от конца и повторите попытку.
sub last_x_lines {
my ($filename, $lineswanted) = @_;
my ($line, $filesize, $seekpos, $numread, @lines);
open F, $filename or die "Can't read $filename: $!\n";
$filesize = -s $filename;
$seekpos = 50 * $lineswanted;
$numread = 0;
while ($numread < $lineswanted) {
@lines = ();
$numread = 0;
seek(F, $filesize - $seekpos, 0);
<F> if $seekpos < $filesize; # Discard probably fragmentary line
while (defined($line = <F>)) {
push @lines, $line;
shift @lines if ++$numread > $lineswanted;
}
if ($numread < $lineswanted) {
# We didn't get enough lines. Double the amount of space to read from next time.
if ($seekpos >= $filesize) {
die "There aren't even $lineswanted lines in $filename - I got $numread\n";
}
$seekpos *= 2;
$seekpos = $filesize if $seekpos >= $filesize;
}
}
close F;
return @lines;
}
P. S. А лучшим названием было бы что-то вроде "читая строки от конца большого файла в Perl".
вы можете использовать модуль Tie::File я считаю. Похоже, что это загружает строки в массив, тогда вы можете получить размер массива и обработать массивы-ze-1000 до arraySize-1.
другой вариант-подсчитать количество строк в файле, затем выполнить цикл через файл один раз и начать чтение значений в numberofLines-1000
$count = `wc -l < $file`;
die "wc failed: $?" if $?;
chomp($count);
Это даст вам количество строк (в большинстве систем.
Если вы знаете количество строк в файле, вы можете сделать
perl -ne "print if ($. > N);" filename.csv
где N - $num_lines_in_file - $num_lines_to_print. Вы можете считать строки с
perl -e "while (<>) {} print $.;" filename.csv
модули-это путь. Однако иногда вы можете писать фрагмент кода, который хотите запустить на различных машинах, на которых могут отсутствовать более неясные модули CPAN. В этом случае почему бы просто не "хвост" и не сбросить вывод во временный файл из Perl?
#!/usr/bin/perl
`tail --lines=1000 /path/myfile.txt > tempfile.txt`
у вас тогда есть что-то, что не зависит от модуля CPAN, если установка может представить проблему.
не полагаясь на хвост, что я, вероятно, сделал бы, если у вас больше $FILESIZE [2GB?] памяти тогда я бы просто ленился и делал:
my @lines = <>;
my @lastKlines = @lines[-1000,-1];
хотя и другие ответы с участием tail
или
seek()
в значительной степени способ пойти на это.
вы должны абсолютно использовать File:: Tail или, еще лучше, другой модуль. Это не скрипт, это модуль (библиотека Программирование). Вероятно, он работает на Windows. Как кто-то сказал, Вы можете проверить это на тестерах CPAN, или часто просто прочитав документацию модуля или просто попробовав его.
вы выбрали использование утилиты tail в качестве предпочтительного ответа, но это, вероятно, будет больше головной боли в Windows, чем File::Tail.