ПРОСТОЕ чтение файлов в Perl - PullRequest
13 голосов
/ 11 мая 2010

Как Perl читает в файлах, как он говорит ему перейти к следующей строке в текстовом файле, и как он заставляет его читать все строки в файле .txt, например, до тех пор, пока он не достигнет элемента "банан"«

Ответы [ 3 ]

21 голосов
/ 11 мая 2010

В принципе, есть два способа чтения файлов:

  1. Хлопание файла означает чтение файла одновременно. Это занимает много памяти и занимает некоторое время, но после этого все содержимое файла находится в памяти, и вы можете делать с ним все, что хотите.
  2. Чтение файла строка за строкой (в цикле 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's 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: $!";

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

19 голосов
/ 11 мая 2010

Рене и Конерак написали пару довольно хороших ответов, которые показывают, как открыть и прочитать файл. К сожалению, у них есть некоторые проблемы с точки зрения продвижения лучших практик. Итак, я опоздаю на вечеринку и попытаюсь добавить четкое объяснение подхода наилучшей практики и почему лучше использовать подход наилучшей практики.

Что такое дескриптор файла?

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 разработан, чтобы дать вам гибкость, чтобы делать то, что вы хотите, когда вы хотите. Это очень разрешительно. Хорошая вещь об этом - то, что вы можете проникнуть в темные глубины и делать действительно крутые магические вещи. Плохо то, что легко выстрелить себе в ногу, если вы забудете умерить изобилие и не сможете сосредоточиться на создании читабельного кода.

Если у вас более чем достаточно веревки, это не значит, что вы должны повеситься.

1 голос
/ 11 мая 2010

Сначала вы должны открыть файл:

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 не определено после прочтения последней строки. Таким образом, вы можете поместить все это в цикл while:

while (my $next_line = <$SOME_FILEHANDLE>) {
  do_something($next_line);
}

Это работает, потому что неопределенное значение оценивается как false в состоянии while.

Если вы хотите выйти из цикла при обнаружении «банана», вы, вероятно, будете использовать регулярное выражение для проверки банана:

while (my $next_line = <$SOME_FILEHANDLE>) {
  last if $next_line =~ /banana/;
  do_something($next_line);
}

Оператор last выходит из цикла while, и он «срабатывает», когда $next_line соответствует банану.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...