这更多是关于如何不这样做的建议。我刚刚在一个相当大的 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;
oderclose 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};
正确关闭文件句柄。