Это скорее предложение, как этого НЕ делать. Мне просто не удалось найти ошибку в довольно большом 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};
который правильно закрывает дескриптор файла.