文件句柄第二次读取失败

时间:2019-02-25 08:32:19

标签: regex perl

如何在Perl的foreach循环内第二次从文件句柄读取?

foreach $a (@b){
    while(my $line = <IN>){
        if($line = /$a/){
            print $line;
        }
    }
}

以上代码未处理列表@b中的第二个元素。如何使其成为可能?

2 个答案:

答案 0 :(得分:5)

您的内部循环while(my $line = <IN>)IN句柄中提取行,直到到达文件末尾为止。

当外部循环foreach $a (@b)尝试再次从IN读取时,它仍在文件末尾。 foreach循环的第一次迭代消耗了文件中的所有行,而其他迭代则没有任何内容。

有几种方法可以解决此问题:

  • Seek回到IN的开头,然后尝试再次读取它:

    foreach $a (@b){
        seek IN, 0, 0
            or die "Cannot seek(): $!";
        while (my $line = <IN>) {
            ...
        }
    }
    

    但是,这仅适用于真实文件,不适用于管道,套接字或终端。

  • 将整个文件读入内存,然后遍历普通数组:

    my @lines = <IN>;
    foreach $a (@b){
        foreach my $line (@lines) {
            ...
        }
    }
    

    但是,如果文件很大,则会占用大量内存。

  • 切换两个循环的顺序:

    while (my $line = <IN>) {
        foreach $a (@b) {
            ...
        }
    }
    

    这是我的最爱。现在,您只需要从文件中读取一次。 @b已经在内存中,因此您可以根据需要对其进行多次迭代。


旁注:

  • 请勿使用IN之类的裸字文件句柄。普通变量(例如$IN)在各个方面都优越得多。
  • 请勿使用名为$a$b的变量。它们有点特殊,因为Perl在sort中使用了它们。
  • 我个人的喜好是永远不要使用< >。它很奇怪地重载(根据您使用的确切语法,它可能表示readlineglob),并且不是很直观。使用readline意味着永远不会有语法上的歧义,即使没有Perl经验的程序员也无法弄清楚它的作用。

有了这些更改:

while (my $line = readline $IN) {
    foreach my $re (@regexes) {
        if ($line =~ /$re/) {
            print $line;
        }
    }
}

答案 1 :(得分:2)

您在edit循环中进行读取,直到文件句柄用尽(到达文件while的结尾)为止。 如果您不关闭并重新打开文件句柄,则在外循环的第二次迭代中将不再读取该文件句柄。

如果从文件句柄读取的数据量不是很大,则可以将文件读入数组变量,然后遍历数组变量的内容。

例如:

EOF

my @filecontent = <IN>; foreach $item_of_b (@b){ foreach my $line_of_file (@filecontent){ if($line_of_file =~ /$item_of_b/){ print $line_of_file; } } } $a不应用作变量名,由于排序,它们是特殊的。