Это скорее совет о том, как НЕ сделать это. Я только что плохо нашел ошибку в довольно большом Perl-приложении. Большинство модулей имели свои собственные файлы конфигурации. Чтобы прочитать файлы конфигурации в целом, я нашел эту строку Perl где-то в Интернете:
# Bad! Don't do that!
my $content = do{local(@ARGV,$/)=$filename;<>};
Переназначает разделитель строк, как описано выше. Но он также переназначает STDIN.
Это имело по крайней мере один побочный эффект, который стоил мне часов, чтобы найти: он не закрывает неявный дескриптор файла должным образом (поскольку он вообще не вызывает close
).
Например, делая это:
use strict;
use warnings;
my $filename = 'some-file.txt';
my $content = do{local(@ARGV,$/)=$filename;<>};
my $content2 = do{local(@ARGV,$/)=$filename;<>};
my $content3 = do{local(@ARGV,$/)=$filename;<>};
print "After reading a file 3 times redirecting to STDIN: $.\n";
open (FILE, "<", $filename) or die $!;
print "After opening a file using dedicated file handle: $.\n";
while (<FILE>) {
print "read line: $.\n";
}
print "before close: $.\n";
close FILE;
print "after close: $.\n";
Результат:
After reading a file 3 times redirecting to STDIN: 3
After opening a file using dedicated file handle: 3
read line: 1
read line: 2
(...)
read line: 46
before close: 46
after close: 0
Странно то, что счетчик строк $.
увеличивается для каждого файла на единицу. Он не сбрасывается и не содержит количества строк. И он не сбрасывается в ноль при открытии другого файла, пока не будет прочитана хотя бы одна строка. В моем случае я делал что-то вроде этого:
while($. < $skipLines) {<FILE>};
Из-за этой проблемы условие было ложным, поскольку счетчик строки не был сброшен должным образом. Я не знаю, является ли это ошибкой или просто неправильным кодом ... Также не помогает вызов close;
oder close STDIN;
.
Я заменил этот нечитаемый код, используя open, сцепление строк и close. Однако решение, опубликованное Брэдом Гилбертом, также работает, поскольку вместо него используется явный дескриптор файла.
Три строки в начале можно заменить на:
my $content = do{local $/; open(my $f1, '<', $filename) or die $!; my $tmp1 = <$f1>; close $f1 or die $!; $tmp1};
my $content2 = do{local $/; open(my $f2, '<', $filename) or die $!; my $tmp2 = <$f2>; close $f2 or die $!; $tmp2};
my $content3 = do{local $/; open(my $f3, '<', $filename) or die $!; my $tmp3 = <$f3>; close $f3 or die $!; $tmp3};
, который правильно закрывает дескриптор файла.