为什么我的Perl脚本会继续读取同一个文件,即使我关闭了它?

adh*_*lon 4 perl file

我正在编写这个获取两个命令行参数的Perl脚本:一个目录和一年.在这个目录中有大量的文本文件或html文件(取决于年份).让我们说比如2010年,它包含的文件看起来像这样<number>rank.html,数字从2001到2212不等.我希望它单独打开每个文件并在html文件中取一部分标题并将其打印到文本文件.但是,当我运行我的代码时,它只会将第一个文件标题打印到文本文件中.它似乎只打开第一个文件2001rank.html而没有其他人.我将在下面发布代码并感谢任何有帮助的人.

my $directory = shift or "Must supply directory\n";
my $year = shift or "Must supply year\n";

unless (-d $directory) {
  die "Error: Directory must be a directory\n";
}

unless ($directory =~ m/\/$/) {
  $directory = "$directory/";
}

open COLUMNS, "> columns$year.txt" or die "Can't open columns file";
my $column_name;

for (my $i = 2001; $i <= 2212; $i++) {

  if ($year >= 2009) {
    my $html_file = $directory.$i."rank.html";
    open FILE, $html_file;

    #check if opened correctly, if not, skip it
    unless (defined fileno(FILE)) {
      print "skipping $html_file\n";
      next;
    }

    $/ = "\n";
    my $line = <FILE>;

    if (defined $line) {
      $column_name = "";
      $_ = <FILE> until m{</title>};
      $_ =~ m{<title>CIA - The World Factbook -- Country Comparison :: (.+)</title>}i;
      $column_name = $1;
    }
    else {
      close FILE;
      next;
    }
    close FILE;
  }
  else {
    my $text_file = $directory.$i."rank.txt";
    open FILE, $text_file;

    unless (defined fileno(FILE)) {
      print "skipping $text_file\n";
      next;
    }

    $/ = "\r";
    my $line = <FILE>;

    if (defined $line) {
      $column_name = "";
      $_ = <FILE> until /Rank/i;
      $_ =~ /Rank(\s+)Country(\s+)(.+)(\s+)Date/i;
      $column_name = $3;
    }
    else {
      close FILE;
      next;
    }
    close FILE;
  }

  print "Adding $column_name to text file\n";
  print COLUMNS "$column_name\n";
}

close COLUMNS;
Run Code Online (Sandbox Code Playgroud)

换句话说$column_name,即使我知道html文件不同,在循环中每次传递都设置相同的东西.

Eth*_*her 5

如果你使用本地词法转换为文件句柄而不是全局变量,你可能能够更快地调试它,以及打开严格检查:

use strict;
use warnings;

while (...)
{
    # ...
    open my $filehandle, $html_file;

    # ...
    my $line = <$filehandle>;
}
Run Code Online (Sandbox Code Playgroud)

这样,在每次循环迭代期间,文件句柄将超出范围,因此您可以更清楚地看到正在引用的内容和位置.(提示:您可能错过了文件句柄关闭的情况,因此下次不正确地重复使用.)

有关open和文件句柄的最佳实践的更多信息,请参阅:

其他一些观点:

  • 不要明确指定$_,那是在惹麻烦.声明自己的变量来保存数据:( my $line = <$filehandle>如上例所示)
  • 直接拿出你匹配到的变量,而不是使用$1,$2等等,只有用括号你真正需要的部分:my ($column_name) = ($line =~ m/Rank\s+Country\s+.+(\s+)Date/i);
  • 首先放置错误条件,因此大部分代码可以缩进一个(或多个)级别.这将提高可读性,因为当您的算法的大部分同时在屏幕上可见时,您可以更好地可视化它正在做什么并捕获错误.

如果您应用以上几点,我很确定您会发现您的错误.我在进行最后一次编辑时发现了它,但我想如果你自己发现它,你会学到更多.(我不是想要傲慢;相信我!)