Какой лучший способ открыть и прочитать файл в Perl?
Обратите внимание: я не ищу "правильный" способ открыть/прочитать файл или как я должен открывать/читать файл каждый раз. Мне просто интересно узнать, как много людей используют, и, возможно, изучать несколько новых методов одновременно:) *
Очень распространенный блок кода в моих программах Perl открывает файл и читает или записывает на него. Я видел так много способов сделать это, и мой стиль выполнения этой задачи несколько раз менялся. Мне просто интересно, какой лучший (если есть лучший способ) способ сделать это?
Я использовал для открытия файла следующим образом:
my $input_file = "/path/to/my/file";
open INPUT_FILE, "<$input_file" || die "Can't open $input_file: $!\n";
Но я думаю, что у него проблемы с захватом ошибок.
Добавление скобок, похоже, устраняет захват ошибок:
open (INPUT_FILE, "<$input_file") || die "Can't open $input_file: $!\n";
Я знаю, что вы также можете назначить дескриптор файла переменной, поэтому вместо использования "INPUT_FILE", как я сделал выше, я мог бы использовать $input_filehandle - это лучше?
Для чтения файла, если он мал, что-то не так с globbing, как это?
my @array = <INPUT_FILE>;
или
my $file_contents = join( "\n", <INPUT_FILE> );
или вы должны всегда прокручиваться, например:
my @array;
while (<INPUT_FILE>) {
push(@array, $_);
}
Я знаю, что в Perl существует так много способов выполнения вещей, мне просто интересно, есть ли предпочтительные/стандартные методы открытия и чтения в файле?
Ответы
Ответ 1
Нет универсальных стандартов, но есть причины предпочесть тот или иной. Моя предпочтительная форма такова:
open( my $input_fh, "<", $input_file ) || die "Can't open $input_file: $!";
Причины:
- Вы сообщаете об ошибках немедленно. (Замените "die" на "warn", если вы этого хотите.)
- Ваш дескриптор файла теперь подсчитывается по ссылке, поэтому, когда вы его не используете, он будет автоматически закрыт. Если вы используете глобальное имя INPUT_FILEHANDLE, вам нужно закрыть файл вручную или он останется открытым до выхода программы.
- Индикатор режима чтения "<" отделен от $input_file, увеличивая удобочитаемость.
Следующее отлично, если файл небольшой, и вы знаете, что хотите все строки:
my @lines = <$input_fh>;
Вы даже можете сделать это, если вам нужно обработать все строки как одну строку:
my $text = join('', <$input_fh>);
Для длинных файлов вам нужно будет перебирать строки с помощью while или использовать read.
Ответ 2
Если вам нужен весь файл как одна строка, нет необходимости перебирать его.
use strict;
use warnings;
use Carp;
use English qw( -no_match_vars );
my $data = q{};
{
local $RS = undef; # This makes it just read the whole thing,
my $fh;
croak "Can't open $input_file: $!\n" if not open $fh, '<', $input_file;
$data = <$fh>;
croak 'Some Error During Close :/ ' if not close $fh;
}
Вышеупомянутое удовлетворяет perlcritic --brutal
, что является хорошим способом проверить "лучшие практики":). $input_file
здесь undefined, но остальное - кошерное.
Ответ 3
Чтобы написать "или умереть", везде сводит меня с ума. Мой предпочтительный способ открыть файл выглядит следующим образом:
use autodie;
open(my $image_fh, '<', $filename);
В то время как это очень мало печатается, есть много важных вещей, которые нужно отметить:
-
Мы используем autodie pragma, что означает, что все встроенные модули Perl выдадут исключение, если что-то идет не так. Это избавляет от необходимости писать or die ...
в вашем коде, создает дружественные сообщения для людей, читаемые с ошибками, и имеет лексическую область действия. Он доступен из CPAN.
-
Мы используем версию с тремя аргументами open. Это означает, что даже если у нас есть забавное имя файла, содержащее символы, такие как <
, >
или |
, Perl будет по-прежнему поступать правильно. В моем учебнике по Perl Security в OSCON я показал несколько способов получить 2-аргумент open
для неправильной работы. Заметки для этого учебника доступны для скачать бесплатно с Perl Training Australia.
-
Мы используем скалярный дескриптор файла. Это означает, что мы не собираемся совпадать с закрытием другого дескриптора файла с тем же именем, что может произойти, если мы используем дескрипторы пакета. Это также означает, что strict
может обнаруживать опечатки и что наш дескриптор файла будет очищен автоматически, если он выходит за рамки.
-
Мы используем значащий дескриптор файла. В этом случае, похоже, мы собираемся записать изображение.
-
Ручка файла заканчивается на _fh
. Если мы увидим, что мы используем его как обычный скаляр, то мы знаем, что это, вероятно, ошибка.
Ответ 4
Если ваши файлы достаточно малы, чтобы можно было прочитать все это в памяти, используйте File:: Slurp. Он читает и записывает полные файлы с помощью очень простого API, а также выполняет все проверки ошибок, поэтому вам не нужно.
Ответ 5
Нет лучшего способа открыть и прочитать файл. Это неправильный вопрос. Что в файле? Сколько данных вам нужно в любой момент? Вам нужны все данные сразу? Что вам нужно делать с данными? Вам нужно выяснить это, прежде чем думать о том, как вам нужно открывать и читать файл.
Что-то, что вы сейчас делаете, вызывает проблемы? Если нет, разве у вас нет проблем решить?:)
Большая часть вашего вопроса - это просто синтаксис, и все ответы на них содержатся в документации Perl (особенно (perlopentut). Вам также может понравиться забрать Learning Perl, который отвечает на большинство проблем, возникающих в вашем вопросе.
Удачи,:)
Ответ 6
Для OO мне нравится:
use FileHandle;
...
my $handle = FileHandle->new( "< $file_to_read" );
croak( "Could not open '$file_to_read'" ) unless $handle;
...
my $line1 = <$handle>;
my $line2 = $handle->getline;
my @lines = $handle->getlines;
$handle->close;
Ответ 7
Верно, что существует как можно больше способов открыть файл в Perl, так как есть
$files_in_the_known_universe * $perl_programmers
... но все же интересно узнать, кто обычно это делает. Моя предпочтительная форма slurping (чтение всего файла сразу):
use strict;
use warnings;
use IO::File;
my $file = shift @ARGV or die "what file?";
my $fh = IO::File->new( $file, '<' ) or die "$file: $!";
my $data = do { local $/; <$fh> };
$fh->close();
# If you didn't just run out of memory, you have:
printf "%d characters (possibly bytes)\n", length($data);
И при переходе по очереди:
my $fh = IO::File->new( $file, '<' ) or die "$file: $!";
while ( my $line = <$fh> ) {
print "Better than cat: $line";
}
$fh->close();
Конечно, лекарь: это всего лишь подходы, которые я посвятил памяти мышц для повседневной работы, и они могут быть радикально непригодны к проблеме, которую вы пытаетесь решить.
Ответ 8
Я когда-то использовал
open (FILEIN, "<", $inputfile) or die "...";
my @FileContents = <FILEIN>;
close FILEIN;
. В настоящее время я использую File::Slurp
для небольших файлов, которые я хочу полностью хранить в памяти, и Tie::File
для больших файлов, которые я хочу для масштабируемого адреса и/или файлов, которые я хочу изменить на месте.
Ответ 9
Прочитайте весь файл $file в переменной $text с помощью одной строки
$text = do {local(@ARGV, $/) = $file ; <>};
или как функция
$text = load_file($file);
sub load_file {local(@ARGV, $/) = @_; <>}
Ответ 10
Если эти программы предназначены только для вашей производительности, все работает! Постройте как можно больше ошибок, как вам кажется.
Чтение в целом файле, если оно велико, может быть не лучшим способом долговременного выполнения, поэтому вы можете обрабатывать строки по мере их поступления, а не загружать их в массив.
Один совет, который я получил из одной из глав в "Прагматическом программисте" (Hunt and Thomas), состоит в том, что вы можете захотеть, чтобы script сохранил резервную копию файла для вас, прежде чем он начнет работу с нарезкой и риском.
Ответ 11
Оператор ||
имеет более высокий приоритет, поэтому он сначала оценивается перед отправкой результата для "открытия"... В коде, который вы упомянули, вместо этого используйте оператор "или", и у вас не было бы эта проблема.
open INPUT_FILE, "<$input_file"
or die "Can't open $input_file: $!\n";
Ответ 12
Дамиан Конвей делает это так:
$data = readline!open(!((*{!$_},$/)=\$_)) for "filename";
Но я не рекомендую это вам.