Как Perl читает в файлах, как он сообщает ему перейти к следующей строке текстового файла и как он заставляет его читать все строки в файле .txt, пока, к примеру, он не достигнет пункта "banana"?
Ответ 1
В принципе, есть два способа чтения файлов:
- Слоение файла означает чтение файла все сразу. Это использует много памяти и занимает некоторое время, но потом все содержимое файла находится в памяти, и вы можете делать то, что хотите с ним.
- Чтение строки строки в строке (в цикле while) лучше, если вы не хотите читать весь файл (например, остановитесь, когда вы достигнете "банана" ).
В обоих случаях вам нужно создать FILEHANDLE с помощью команды "open", например:
open(my $yourhandle, '<', 'path/to/file.txt') # always use a variable here containing filename
or die "Unable to open file, $!";
Затем вы можете либо разложить файл, поместив его в массив:
my @entire_file=<$yourhandle>; # Slurp!
или прочитайте файл один за другим, используя цикл while
while (<$yourhandle>) { # Read the file line per line (or otherwise, it configurable).
print "The line is now in the $_ variable";
last if $_ eq 'banana'; # Leave the while-loop.
}
Затем не забудьте закрыть файл.
close($yourhandle)
or warn "Unable to close the file handle: $!";
Это просто основы... там много общего с файлами, особенно в обработке исключений (что делать, когда файл не существует, не читается, записывается), поэтому вам нужно будет прочитать или попросить прочь:)
Ответ 2
Рене и Konerak написал пару довольно хороших ответов, которые показывают, как открыть и прочитать файл. К сожалению, у них есть некоторые проблемы с точки зрения продвижения передового опыта. Итак, я опоздаю на вечеринку и попытаюсь добавить четкое объяснение подхода к лучшей практике и почему лучше использовать подход с лучшей практикой.
Что такое дескриптор файла?
Дескриптор файла - это имя, которое мы используем, которое представляет сам файл. Когда вы хотите работать с файлом (читать его, записывать в него, перемещаться и т.д.), Используйте дескриптор файла, чтобы указать, какой файл будет работать. Дескриптор файла отличается от имени файла или пути.
Переменная область и файлы
Область переменных определяет, в каких частях программы можно видеть переменную. В общем, неплохо держать область видимости на каждой переменной настолько малой, чтобы разные части сложной программы не нарушали друг друга.
Самый простой способ строго контролировать область переменных в Perl - сделать ее лексической переменной. Лексические переменные видны только внутри блока, в котором они объявлены. Используйте my
для объявления лексической переменной: my $foo;
# Can't see $foo here
{ my $foo = 7;
print $foo;
}
# Can't see $foo here
Perl файлы могут быть глобальными или лексическими. Когда вы используете open с открытым словом (буквальная строка без кавычек или сигила), вы создаете глобальный дескриптор. Когда вы открываете лексический скаляр undefined, вы создаете лексический дескриптор.
open FOO, $file; # Global file handle
open my $foo, $file; # Lexical file handle
# Another way to get a lexical handle:
my $foo;
open $foo, $file;
Большая проблема с глобальными дескрипторами файлов заключается в том, что они видны в любом месте программы. Поэтому, если я создаю дескриптор файла под именем FOO в подпрограмме, я должен очень тщательно убедиться, что я не использую одно и то же имя в другой подпрограмме, или если я использую одно и то же имя, я должен быть абсолютно уверен, что ни при каких обстоятельствах не может они конфликтуют друг с другом. Простой альтернативой является использование лексического дескриптора, который не может иметь одинаковые конфликты имен.
Другим преимуществом лексических дескрипторов является то, что их легко передать в качестве аргументов подпрограммы.
Функция open
Функция open
имеет всевозможные функции. Он может запускать подпроцессы, читать файлы и даже предоставлять дескриптор для содержимого скаляра. Вы можете подавать много разных типов списков аргументов. Он очень мощный и гибкий, но эти функции приходят с некоторыми gotchas (выполнение подпроцессов - это не то, что вы хотите сделать случайно).
Для простого случая открытия файла лучше всегда использовать форму 3-аргумента, поскольку она предотвращает непреднамеренную активацию всех этих специальных функций:
open FILEHANDLE, MODE, FILEPATH
FILEHANDLE
- это дескриптор файла, который нужно открыть.
MODE
заключается в том, как открыть файл, >
для перезаписи, ' → for write in append mode,
+ > for read and write, and
< `для чтения.
FILEPATH
- это путь к открываемому файлу.
При успешном завершении open
возвращает истинное значение. При ошибке $!
устанавливается, чтобы указать ошибку, и возвращается ложное значение.
Итак, чтобы сделать лексический дескриптор файла с 3-аргументом open
, который мы можем использовать для чтения файла:
open my $fh, '<', $file_path;
Значения логического возврата позволяют легко проверить наличие ошибок:
open my $fh, '<', $file_path
or die "Error opening $file_path - $!\n";
Мне нравится приводить обработку ошибок в новую строку и отступы, но этот личный стиль.
Закрывающие ручки
Когда вы используете глобальные дескрипторы, важно тщательно, явно закрывать каждый дескриптор, когда вы закончите с ним. Несоблюдение этого требования может привести к возникновению нечетных ошибок и проблем с ремонтопригодностью.
close FOO;
Лексические ручки автоматически закрываются при уничтожении переменной (когда счетчик ссылок падает до 0, обычно, когда переменная выходит за пределы области видимости).
При использовании лексических ручек обычно полагается на неявное закрытие дескрипторов, а не на их закрытие.
Алмазы - лучший друг Perl.
Алмазный оператор <>
позволяет нам перебирать дескриптор файла. Как open
у него есть сверхспособности. На данный момент мы будем игнорировать большинство из них. (Ищите информацию о разделителе входных записей, разделителе выходной записи и дескрипторе файла NULL, чтобы узнать о них.)
Важно то, что в скалярном контексте (например, присваивании скаляру) он действует как функция readline
. В контексте списка (например, назначение массиву) он действует как функция read_all_lines
.
Представьте, что вы хотите прочитать файл данных с тремя строками заголовка (дата, время и местоположение) и связкой строк данных:
open my $fh, '<', $file_path
or die "Ugh - $!\n";
my $date = <$fh>;
my $time = <$fh>;
my $loc = <$fh>;
my @data = <$fh>;
Общепринято слышать, как люди говорят о разрыве файла. Это означает, что вы сразу читаете весь файл в переменной.
# Slurp into array
my @slurp = <$fh>;
# Slurp into a scalar - uses tricks outside the scope of this answer
my $slurp;
{ local $/ = undef; $slurp = <$fh>; }
Объединяя все это
open my $fh, '<', 'my_file'
or die "Error opening file - $!\n";
my @before_banana;
while( my $line = <$fh> ) {
last if $line =~ /^banana$/;
push @before_banana, $line;
}
Объединяя все это - специальная дополнительная кредитная версия
my $fh = get_handle( 'my_file' );
my @banana = read_until( $fh, qr/^banana$/ ); # Get the lines before banana
read_until( $fh, qr/^no banana$/ ); # Skip some lines
my @potato = read_until( $fh, qr/^potato$/ ); # Get the lines before potato
sub get_handle {
my $file_path = shift;
open my $fh, '<', $file_path
or die "Can't open '$file_path' for reading - $!\n";
return $fh;
}
sub read_until {
my $fh = shift;
my $match = shift;
my @lines;
while( my $line = <$fh> ) {
last if $line =~ /$match/;
push @line, $line;
}
return @lines;
}
Почему так много разных способов? Почему так много ошибок?
Perl - это старый язык; у него есть багажная датировка вплоть до 1987 года. На протяжении многих лет были выявлены различные проблемы с дизайном и исправления, но редко были исправления, позволяющие повредить обратную совместимость.
Кроме того, Perl разработан, чтобы дать вам возможность делать то, что вы хотите, когда захотите. Это очень разрешительно. Хорошая вещь об этом заключается в том, что вы можете спуститься в мрачные глубины и действительно охладить магические вещи. Плохо то, что легко стрелять в ногу, если вы забываете умерить свое изобилие и не сосредоточиться на создании читаемого кода.
Просто потому, что у вас есть более чем достаточно веревки, это не значит, что вы должны повесить себя.
Ответ 3
Сначала вы должны открыть файл:
open (my $SOME_FILEHANDLE, "<", "filename.txt");
Возможно, вы захотите проверить, было ли успешным открытие файла:
open (my $SOME_FILEHANDLE, "<", "filename.txt") or die "could not open filename";
После открытия файла вы можете прочитать строку в строке из $SOME_FILEHANDLE. Вы получите следующую строку с конструкцией <$SOME_FILEHANDLE>
:
my $next_line = <$SOME_FILEHANDLE>;
$next_line
- undefined после прочтения последней строки. Итак, вы можете поместить все это в цикл while
:
while (my $next_line = <$SOME_FILEHANDLE>) {
do_something($next_line);
}
Это работает, потому что значение undefined оценивается как false
в условии while.
Если вы хотите выйти из цикла, когда встречается "банан", вы, вероятно, будете использовать регулярное выражение для проверки банана:
while (my $next_line = <$SOME_FILEHANDLE>) {
last if $next_line =~ /banana/;
do_something($next_line);
}
Оператор last
завершает цикл while и запускается, когда $next_line
соответствует банану.