文件句柄与子例程调用一起出现意外行为 - 为什么?

时间:2016-01-20 08:15:15

标签: perl

我正在逐行读取文件,并希望通过子程序处理每一行。由于我对行本身不感兴趣,因此我将文件句柄中的读取直接放入子例程调用中。然而,这导致了我不太了解的意外行为。

我创建了一个演示效果的最小例子:

#!/usr/bin/perl

use strict;
use warnings;
use Carp;
use English qw( -no_match_vars );

print "This works as expected:\n";

open my $TEST1, '<', 'filetest1.txt' or croak "Can't open filetest1.txt - $ERRNO";          

my $line1 = <$TEST1>;
print_line( $line1 );

while ( 1 ) {
    last if eof $TEST1; 
    $line1 = <$TEST1>;
    print $line1;
}
close $TEST1;

print "\n";
print "Unexpected effect here:\n";
open my $TEST2, '<', 'filetest1.txt' or croak "Can't open filetest1.txt - $ERRNO";          

print_line(<$TEST2>); # this works, but just once

while ( 1 ) {
    last if eof $TEST2; # is triggered immediately
    print "This is never printed\n";
    print_line(<$TEST2>);
}
close $TEST2;

sub print_line {
    my $line = shift;
    print $line;
    return 1;
}

filetest1.txt的内容:

test line 1
test line 2
test line 3
test line 4
test line 5

脚本结果:

This works as expected:
test line 1
test line 2
test line 3
test line 4
test line 5
Unexpected effect here:
test line 1

似乎当我在子程序调用中直接读取下一行时,它只运行一次然后触发eof。我没有找到任何关于该效果的解释,它迫使我创建变量$ line1只是为了将该行传递给子例程。

我正在寻找解释为什么会发生这种情况的原因,因此我想了解我对文件句柄能做什么或不能做什么的限制。

2 个答案:

答案 0 :(得分:3)

在您的代码print_line(<$FH>);中,文件句柄的读取将以wantarray模式完成,这意味着您不会读取整行文件的单行。在您的子程序中,您只需使用第一行并丢弃其余部分。这就是为什么在第一次循环遇到后文件句柄是空的。

您可以将文件句柄提供给子例程并在那里读取一行:

open my $FH , '<' , 'somefile' or die "Cannot read: $!" ;
while( ! eof $FH ) {
  print_line( $FH ) ;
}

sub print_line {
  my ( $fh ) = @_ ;

  my $line = <$fh> ;
  print $line ;
}

答案 1 :(得分:1)

您遇到了上下文问题。 $TEST1读取位于标量上下文中,因此它只读取一行。 $TEST2读取位于列表上下文中,因此将读取文件中的所有行,并调用print_line()并将其列表作为其参数。因此,当您第二次尝试从$TEST2读取时,您会获得EOF,因为所有行都是第一次读取。