これは、そうしない方法についてのより多くの提案です。かなり大きな Perl アプリケーションでバグを見つけるのに苦労しました。ほとんどのモジュールには独自の構成ファイルがありました。構成ファイル全体を読むために、インターネット上のどこかで次の Perl の行を見つけました。
# Bad! Don't do that!
my $content = do{local(@ARGV,$/)=$filename;<>};
前に説明したように、行区切りを再割り当てします。ただし、STDIN も再割り当てします。
これには少なくとも 1 つの副作用があり、見つけるのに何時間もかかりました: 暗黙的なファイル ハンドルを適切に閉じません (まったく呼び出さないため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
$.
奇妙なことに、ファイルごとに行カウンターが 1 ずつ増えます。リセットされず、行数は含まれません。また、別のファイルを開いたときに、少なくとも 1 行が読み込まれるまではゼロにリセットされません。私の場合、私は次のようなことをしていました:
while($. < $skipLines) {<FILE>};
この問題により、ライン カウンタが適切にリセットされなかったため、条件は false でした。これがバグなのか、単に間違ったコードなのかはわかりません...また、close;
oderを呼び出しclose STDIN;
ても役に立ちません。
この判読不能なコードを、open、string concatenation、および close を使用して置き換えました。ただし、代わりに明示的なファイル ハンドルを使用するため、Brad Gilbert によって投稿されたソリューションも機能します。
先頭の 3 行は、次のように置き換えることができます。
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};
ファイルハンドルを適切に閉じます。