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

Давайте узнаем, почему так делают, в чем там проблема и почему следует этого избегать.

Так что же делать?

Прежде чем рассказывать, как делать не надо, позвольте дать ссылки на статьи, в которых объясняется, как делать надо:

Прочитайте, как открывать файлы современным способом и как в Perl открывать файлы для записи.

Теперь давайте вернемся к старым, и уже-не-таким-хорошим практикам.

Старый, не рекомендуемый к использованию способ

До выхода perl 5.6 - то есть до 2000 года - чтобы открыть файл для записи, мы писали такой код:

open OUT, ">$filename" or die ...;

и так для чтения:

open IN, $filename or die ...;

Часть «or die» с тех пор не изменилась, здесь мы ее целиком не пишем.

Как вы видите, open принимает два параметра. Первый - это последовательность букв (обычно в верхнем регистре). Сюда попадет файловая ссылка. Второй - комбинация режима открытия и пути к открываемому файлу.

На деле, в первом случае мы видим знак «больше», означающий, что мы открываем файл для записи, но во втором примере мы пропустили режим открытия. Это из-за того, что open() по умолчанию использует режим чтения.

Здесь два больших отличия от изученной нами практики:

Глобальная файловая ссылка

Первое состоит в использовании для файловой ссылки странной переменной без $ в начале. (По сути, это bareword, но он не вызывает ошибки Bareword not allowed while "strict subs" in use.)

Это по-прежнему работает, как и в прежние времена, но есть некоторые связанные с этим проблемы:

Использованная переменная становится глобальной для всего скрипта, так что если кто-то использует для своей переменной то же имя (в нашем примере это IN или OUT), то она перекроется с вашей.

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

open с двумя параметрами

Второе отличие это то, что в этих примерах в open передается только два параметра.

Что если переменная $filename, которую мы использовали в открытии файла для чтения, содержит >/etc/passwd ?

Ой.

Строка open IN, $filename откроет этот файл для записи.

Мы только что удалили файл с паролями на нашем Linux'е.

Это нехорошо.

Нужно закрывать файловую ссылку

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

Как избегать этих проблем?

Лучше всего избегать использования обеих этих праткик, и использовать «новый» (появившийся в 2000 году!) open с тремя параметрами и скалярную лексическую переменную для открытия файлов и хранения файловой ссылки.

В Perl::Critic даже есть политики, которые помогут вам проанализировать код и найти все места, где кто-то использовал одну из форм, приведенных выше.

Хорошее и Плохое чтение

Плохое:

open IN, $filename or die ...;

Хорошее:

open my $in, '<', $filename or die ...;

Хорошая и Плохая запись

Плохая:

open IN, ">$filename" or die ...;

Хорошая:

open my $in, '>', $filename or die ...;