【问题标题】:confusing filehandle in perlperl中令人困惑的文件句柄
【发布时间】:2015-06-06 15:25:15
【问题描述】:

一直在玩下面的脚本,但仍然无法理解这两种不同“种类”的文件句柄形式背后的含义。任何见解都将不胜感激。

#! usr/bin/perl
use warnings;
use strict;
open (FH, "example.txt") or die $!;

while (<FH>) {
    my @line = split (/\t/, $_); {
        print "@line","\n";
    }
}

输出如预期:@line 数组包含来自example.txt 的第 1,2,3 行的元素...。有人告诉我 open (FH, example.txt) 不如 open (my $fh, '&lt;', 'example.txt') 好,我更改了它,但随后出现了混乱。

根据我的发现,$fhscalar 并包含example.txt 中的所有信息。当我将一个数组分配给$fh 时,该数组将example.txt 中的每一行存储为数组中的一个组件。但是,当我尝试将组件进一步拆分为“更多组件”时,我收到了错误/警告消息“use of uninitialized value”。下面是显示错误/警告消息的实际脚本。

open (my $fh, '<', 'example.txt') or die $!;
foreach ($fh) {
    my @line = <$fh>;
    my $count = 0;
    for $count (0..$#line) {
        my @line2 = split /\t/, $line[$count];
        print "@line2";
        print "$line2[0]";
        }
    }

print "@line2" 显示预期的输出,但print "$line2[0]" 调用错误/警告消息。我想如果@line2 是一个真正的数组,$line2[0] 应该没问题。但是为什么是“未初始化的值”??

任何帮助将不胜感激。非常感谢。

添加 - 以下是“实际”脚本(我重新运行它并且警告在那里)

#! usr/bin/perl
use warnings;
use strict;
open (my $fh, '<', 'example.txt') or die $!;

foreach ($fh) {
    my @line = <$fh>;
    print "$line[1]";
    my $count = 0;
    for my $count (0..$#line) {
    my @line2 = split /\t/, $line[$count];
    print "@line2";
    #my $line2_count = $#line2;
    #print $line2_count;
    print "$line2[3]";
    }
    }

警告仍然是use of uninitialized value $line2[3] in string at filename.pl line 15, &lt;$fh&gt; line3

【问题讨论】:

  • 你确定吗?我能够毫无问题地运行相同的代码。
  • 使用 foreach 的第二个示例没有任何意义,并且存在您的问题,而不是打开三个 args。 while() .. 以与 globtype 相同的方式从文件句柄标量中读取数据。
  • @Сухой27,foreach ($fh) { } 毫无意义,只是因为它什么也没做。除了可读性之外,它不会造成任何损害。
  • @B Chen,如果$line[$count] 是一个空字符串,那么您可以获得该警告的唯一方法,但这是不可能的。它至少包含一个换行符。您发布的代码没有产生您声称的错误。请发布实际产生警告的代码以及必要的数据。

标签: arrays perl filehandle


【解决方案1】:

在您的第二个示例中,您正在列表上下文中读取文件句柄,我认为这是您问题的根源。

my $line = <$fh>;

从文件句柄中读取一行。

my @lines = <$fh>;

读取所有文件。 你以前的例子,感谢

while (<FH>) {

正在有效地处理第一种情况。

但是在第二个示例中,您正在做第二件事。

【讨论】:

    【解决方案2】:

    AFAIK,您应该始终使用

    while (<FH>) {
       # use $_ to access the content
    }
    

    或更好

    while(my $single_line = <FH>) {
       # use $single_line to access the content
    }
    

    因为 while 逐行读取其中 for 首先将所有内容加载到内存中并在之后对其进行迭代。

    即使在 EOF 或错误时返回 undef,当未明确完成时,解释器也会添加对 undef 的检查。

    因此,使用 while 可以毫无问题地加载多 GB 的日志文件,并且不会浪费 RAM,而使用需要迭代数组的 for 循环则不能。

    至少这是我从几年前读过的 Perl 书中的记忆。

    【讨论】:

    • while (my $line = &lt;FH&gt;)while(defined(my $line = &lt;FH&gt;))没有区别。
    • 正确地做总是更好。我不再有任何影响,但在旧的 perl 版本中:#!/usr/bin/env perl use strict; use warnings; open(FH, "test.txt") or die "ERROR: $!"; while (&lt;FH&gt;) { print "----" . $_ . "+++"; } 变为:$ perl -MO=Deparse ~/Desktop/testMe.pl use warnings; use strict; die "ERROR: $!" unless open FH, 'test.txt'; while (defined($_ = &lt;FH&gt;)) { print '----' . $_ . '+++'; } testMe.pl syntax OK 并且花边 while (my $line = &lt;FH&gt;) 也将转换为 while(defined(my $line = &lt;FH&gt;))
    • stackoverflow.com/questions/9621221/… 那么为什么不按照旧的 perl 书籍告诉你的那样正确地做呢?
    • 至少 2010 年仍然如此,而 2010 年也不是很久以前。请参阅“有效的 Perl 编程:编写更好、更惯用的 Perl 的方法,第二版作者:Joseph N. Hall;Joshua A. McAdams;brian d foy 有效的 Perl 编程”第 1 章。Perl 基础;第 7 项. 知道哪些值是错误的并相应地测试它们
    • 作为写你参考的书的人,我说听思南,因为他告诉你一些比一般规则更具体的东西。您的版本或多或少不是稳定的,因为它是相同的。这是一个记录在案的特殊情况,大多数知道自己在做什么的人都会写。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-11
    • 2016-08-31
    • 2017-01-17
    • 1970-01-01
    相关资源
    最近更新 更多