Рене и Конерак написали пару довольно хороших ответов, которые показывают, как открыть и прочитать файл. К сожалению, у них есть некоторые проблемы с точки зрения продвижения лучших практик. Итак, я опоздаю на вечеринку и попытаюсь добавить четкое объяснение подхода наилучшей практики и почему лучше использовать подход наилучшей практики.
Что такое дескриптор файла?
A дескриптор файла - это имя, которое мы используем, которое представляет сам файл. Если вы хотите работать с файлом (читать его, писать в него, перемещаться и т. Д.), Используйте дескриптор файла, чтобы указать, над каким файлом работать. Дескриптор файла отличается от имени файла или пути.
Переменная область и дескрипторы файла
Область действия переменной определяет, в каких частях программы переменная может быть видна. В целом, желательно, чтобы область действия каждой переменной была как можно меньше, чтобы разные части сложной программы не ломали друг друга.
Самый простой способ строго контролировать область действия переменной в Perl - это сделать ее лексической переменной . Лексические переменные видны только внутри блока, в котором они объявлены. Используйте my
для объявления лексической переменной: my $foo;
# Can't see $foo here
{ my $foo = 7;
print $foo;
}
# Can't see $foo here
Дескрипторы файла Perl могут быть глобальными или лексическими. Когда вы используете open с голым словом (буквальная строка без кавычек или сигил), вы создаете глобальный дескриптор. Когда вы открываете неопределенный лексический скаляр, вы создаете лексический дескриптор.
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
имеет все виды функций. Он может запускать подпроцессы, читать файлы и даже предоставлять дескриптор для содержимого скаляра. Вы можете кормить его множеством разных типов списков аргументов. Он очень мощный и гибкий, но эти функции имеют некоторые недостатки (выполнение подпроцессов - это не то, что вы хотите делать случайно).
Для простого случая открытия файла лучше всегда использовать форму с тремя аргументами, поскольку она предотвращает непреднамеренную активацию всех этих специальных функций:
open FILEHANDLE, MODE, FILEPATH
FILEHANDLE
- дескриптор файла, который нужно открыть.
MODE
- как открыть файл, >
для перезаписи, '>> for write in append mode,
+> for read and write, and
<`для чтения. </p>
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.
Оператор diamond, <>
, позволяет перебирать дескриптор файла. Как и 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 разработан, чтобы дать вам гибкость, чтобы делать то, что вы хотите, когда вы хотите. Это очень разрешительно. Хорошая вещь об этом - то, что вы можете проникнуть в темные глубины и делать действительно крутые магические вещи. Плохо то, что легко выстрелить себе в ногу, если вы забудете умерить изобилие и не сможете сосредоточиться на создании читабельного кода.
Если у вас более чем достаточно веревки, это не значит, что вы должны повеситься.