这更多是关于如何不这样做的建议。我只是在一个相当大的Perl应用程序中发现错误的时间很短。大多数模块都有自己的配置文件。要整体读取配置文件,我在Internet上的某处找到了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;
也无济于事。
我使用打开,字符串连接和关闭替换了此不可读的代码。但是,Brad Gilbert发布的解决方案也可以使用,因为它使用显式文件句柄代替。
开头的三行可以替换为:
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};
可以正确关闭文件句柄。