นี่เป็นข้อเสนอแนะเพิ่มเติมเกี่ยวกับวิธีไม่ทำ ฉันมีช่วงเวลาที่เลวร้ายในการค้นหาจุดบกพร่องในแอปพลิเคชัน 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;
ก็ไม่ช่วยอะไร
ฉันแทนที่โค้ดที่อ่านไม่ได้นี้โดยใช้การเปิดการต่อสตริงและปิด อย่างไรก็ตามโซลูชันที่โพสต์โดย 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};
ซึ่งจะปิดที่จับไฟล์อย่างถูกต้อง