Đây là một gợi ý về cách KHÔNG làm điều đó. Tôi đã có một thời gian tồi tệ khi tìm thấy một lỗi trong một ứng dụng Perl khá lớn. Hầu hết các mô-đun có tập tin cấu hình riêng. Để đọc toàn bộ các tệp cấu hình, tôi tìm thấy dòng Perl này ở đâu đó trên Internet:
# Bad! Don't do that!
my $content = do{local(@ARGV,$/)=$filename;<>};
Nó gán lại dấu phân cách dòng như đã giải thích trước đó. Nhưng nó cũng gán lại STDIN.
Điều này có ít nhất một tác dụng phụ khiến tôi mất hàng giờ để tìm: Nó không đóng tệp xử lý ẩn đúng cách (vì nó hoàn toàn không gọi close
).
Ví dụ: làm điều đó:
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";
kết quả trong:
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
Điều kỳ lạ là, bộ đếm dòng $.
được tăng cho mỗi tệp một. Nó không được thiết lập lại và nó không chứa số lượng dòng. Và nó không được đặt lại về 0 khi mở tệp khác cho đến khi ít nhất một dòng được đọc. Trong trường hợp của tôi, tôi đã làm một cái gì đó như thế này:
while($. < $skipLines) {<FILE>};
Do vấn đề này, điều kiện là sai vì bộ đếm dòng không được đặt lại đúng. Tôi không biết đây là lỗi hay đơn giản là mã sai ... Ngoài ra, việc gọi close;
oder close STDIN;
không giúp ích gì.
Tôi đã thay thế mã không thể đọc được này bằng cách sử dụng mở, nối chuỗi và đóng. Tuy nhiên, giải pháp được đăng bởi Brad Gilbert cũng hoạt động vì nó sử dụng xử lý tệp rõ ràng thay thế.
Ba dòng ở đầu có thể được thay thế bằng:
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};
mà đóng đúng cách xử lý tập tin.