Какой лучший способ открыть и прочитать файл в Perl? - PullRequest
43 голосов
/ 25 ноября 2008

Обратите внимание - я не ищу «правильный» способ открыть / прочитать файл или способ, которым я должен открывать / читать файл каждый раз. Мне просто интересно узнать, каким образом большинство людей используют, и, возможно, изучить несколько новых методов одновременно:) *

Очень распространенный блок кода в моих программах на 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 - это лучше?

Для чтения файла, если он маленький, что-то не так с глобализацией, как это?

my @array = <INPUT_FILE>;

или

my $file_contents = join( "\n", <INPUT_FILE> );

или вы всегда должны проходить, как это:

my @array;
while (<INPUT_FILE>) {
  push(@array, $_);
}

Я знаю, что в Perl так много способов сделать что-то, мне просто интересно, есть ли предпочтительные / стандартные методы открытия и чтения в файле?

Ответы [ 12 ]

58 голосов
/ 25 ноября 2008

Универсальных стандартов не существует, но есть причины отдавать предпочтение тем или иным. Моя предпочтительная форма это:

open( my $input_fh, "<", $input_file ) || die "Can't open $input_file: $!";

Причины:

  • Вы немедленно сообщаете об ошибках. (Замените «die» на «warn», если вы этого хотите.)
  • Ваш файловый дескриптор теперь сосчитан по ссылке, поэтому, если вы его не используете, он будет автоматически закрыт. Если вы используете глобальное имя INPUT_FILEHANDLE, то вам придется закрыть файл вручную, или он останется открытым до выхода из программы.
  • Индикатор режима чтения "<" отделен от файла $ input_file, что повышает удобочитаемость. </li>

Следующее замечательно, если файл маленький, и вы знаете, что хотите все строки:

my @lines = <$input_fh>;

Вы даже можете сделать это, если вам нужно обработать все строки как одну строку:

my $text = join('', <$input_fh>);

Для длинных файлов вы захотите перебирать строки с while или использовать read.

15 голосов
/ 26 ноября 2008

Если вы хотите, чтобы весь файл представлял собой одну строку, нет необходимости перебирать его.

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 здесь все еще не определено, но все остальное кошерное.

13 голосов
/ 29 ноября 2008

Необходимость писать «или умирать» везде сводит меня с ума. Мой предпочтительный способ открыть файл выглядит так:

use autodie;

open(my $image_fh, '<', $filename);

Несмотря на то, что печатать очень мало, нужно отметить много важных вещей:

  • Мы используем прагму autodie , которая означает, что все встроенные в Perl вызовут исключение, если что-то пойдет не так. Это устраняет необходимость в написании or die ... в вашем коде, оно создает дружественные, понятные человеку сообщения об ошибках и имеет лексическую область видимости. Это доступно из CPAN.

  • Мы используем версию open с тремя аргументами. Это означает, что даже если у нас есть смешное имя файла, содержащее такие символы, как <, > или |, Perl все равно поступит правильно. В моем уроке Perl Security в OSCON я показал несколько способов, как заставить 2-аргумент open вести себя неправильно. Примечания к этому руководству доступны для бесплатной загрузки с Perl Training Australia .

  • Мы используем скалярный дескриптор файла. Это означает, что мы не будем одновременно закрывать чужой дескриптор файла с тем же именем, что может случиться, если мы используем дескрипторы файла пакета. Это также означает, что strict может обнаружить опечатки, и что наш дескриптор файла будет очищен автоматически, если он выходит из области видимости.

  • Мы используем значимый дескриптор файла. В этом случае похоже, что мы собираемся записать изображение.

  • Дескриптор файла заканчивается на _fh. Если мы увидим, что мы используем его как обычный скаляр, то мы знаем, что это, вероятно, ошибка.

11 голосов
/ 26 ноября 2008

Если ваши файлы настолько малы, что возможно чтение всего в память, используйте File :: Slurp . Он читает и записывает полные файлы с очень простым API, плюс выполняет всю проверку ошибок, поэтому вам не нужно.

6 голосов
/ 26 ноября 2008

Нет лучшего способа открыть и прочитать файл. Это неправильный вопрос. Что в файле? Сколько данных вам нужно в любой момент? Вам нужны все данные одновременно? Что вам нужно делать с данными? Вы должны выяснить это, прежде чем думать о том, как вам нужно открыть и прочитать файл.

Что-то, что вы делаете сейчас, вызывает у вас проблемы? Если нет, разве у вас нет проблем лучше решить? :)

Большая часть вашего вопроса - просто синтаксис, и на все это есть ответы в документации по Perl (особенно ( perlopentut ). Вы также можете выбрать Learning Perl , который отвечает на большинство из проблем, которые у вас есть в вашем вопросе.

Удачи, :)

5 голосов
/ 26 ноября 2008

Действительно, в Perl существует столько же лучших способов открыть файл, сколько и

$files_in_the_known_universe * $perl_programmers

... но все равно интересно посмотреть, кто это обычно делает. Моя предпочитаемая форма слэпинга (чтение всего файла сразу):

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();

Предостережение лектора, конечно: это именно те подходы, которые я придерживался к мышечной памяти для повседневной работы, и они могут в корне не соответствовать проблеме, которую вы пытаетесь решить.

5 голосов
/ 26 ноября 2008

Мне нравится:

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;
4 голосов
/ 26 ноября 2008

Я однажды использовал

open (FILEIN, "<", $inputfile) or die "...";
my @FileContents = <FILEIN>;
close FILEIN;

регулярно. В настоящее время я использую File::Slurp для небольших файлов, которые я хочу полностью хранить в памяти, и Tie::File для больших файлов, которые я хочу масштабировать, и / или файлов, которые я хочу изменить на месте.

3 голосов
/ 30 ноября 2008

Считать весь файл $ file в переменную $ text одной строкой

$text = do {local(@ARGV, $/) = $file ; <>};

или как функция

$text = load_file($file);
sub load_file {local(@ARGV, $/) = @_; <>}
2 голосов
/ 01 декабря 2008

Оператор || имеет более высокий приоритет, поэтому он сначала оценивается перед отправкой результата в «open» ... В упомянутом коде вместо этого используйте оператор «или», и у вас не будет эта проблема.

open INPUT_FILE, "<$input_file"
  or die "Can't open $input_file: $!\n";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...