Подтвердить что ты не робот

Какой лучший способ открыть и прочитать файл в 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 существует так много способов выполнения вещей, мне просто интересно, есть ли предпочтительные/стандартные методы открытия и чтения в файле?

4b9b3361

Ответ 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";

Но я не рекомендую это вам.