【问题标题】:How to open a file which name is found in another file, recursively如何以递归方式打开在另一个文件中找到名称的文件
【发布时间】:2018-10-07 03:27:10
【问题描述】:

递归文件打开而不破坏 perl 中的文件句柄

#!usr/bin/perl
   $set=1; 
   open (MYFILE, 'file1.txt'); 
   $array[$set]=\*MYFILE; 
   printit ($array[$set]); 

   sub printit {    
     ($array[$set])=shift;    
     $fh=<$array[$set]>;
     while (<$fh>) {
       chomp($fh); 
       #print data in the file
       if($fh=~/\.txt/){
           #print $fh;
           open (files,"$fh");
           $set=$set+1;
           printit(*files);
           $set=$set-1;
          }
    } 
}   
file1.txt -file2.txt,file3.txt #假设 file2.txt 在 file3.txt 之前 文件2.txt-文件4.txt 文件3.txt

我想打开一个 file1.txt 并在 file1 中打印数据,如果我找到 文件中的 file2.txt 打开文件打印数据并递归执行 直到文件中不包含 .txt 文件并返回 (横切一棵树)在我们的例子中 file1->file2->file4->file3->file1 end 程序。我不知道为什么我的程序不起作用。提前致谢*

【问题讨论】:

  • 使用严格和警告,它可能会在这里发现几个问题。不要使用裸字(全局)文件句柄或全局变量(它们应该用my 声明),并错误检查您的打开:使用open my $file, 'file1.txt' or die "Open file1.txt failed: $!";。 &lt;$array[$set]&gt; 不起作用,因为 &lt;&gt; 运算符有奇怪的解析规则并将其解释为一个 glob,您可以改为使用 readline($array[$set])(它是相同的操作)。
  • 请格式化解释,使其可读...?至少开始,我们会提供帮助。我试图编辑,但我无法完全理解它。
  • “不破坏文件句柄”是什么意思?全部保留,打开?请澄清。
  • 我确实清理并格式化了您的问题,但我不明白文件列表。请编辑以澄清。 (如果您不喜欢我的编辑,您可以点击问题正下方的“已编辑(时间)”链接撤消它,然后点击之前版本下的“回滚”)
  • 始终使用use strict; use warnings qw( all );!!!

标签: file perl recursion filehandle recursive-datastructures


【解决方案1】:

我对这个问题的看法:读取一个文件,如果找到文件名(由.txt 判断)打开并读取它们,然后递归地继续。发布的代码有一些基本错误,如下所述。

我假设需要先打印文件的所有行,然后我们进入下一个文件(如果找到)。下面的代码允许关闭文件句柄;它的细微变化将它们保持在一个数组中并在下面打开。

use warnings;
use strict;
use feature 'say';

my $file = shift @ARGV || 'file.txt';

open my $fh, '<', $file or die "Can't open $file: $!";

recurse_open($fh);

sub recurse_open {
    my ($fh) = shift;
    my @files;
    while (<$fh>) {
        print;
        if (/\b(.+?\.txt)\b/) {
            push @files, $1; 
        }   
    }   
    say '---';
    foreach my $file (@files) {
        open my $fh_next, '<', $file  or do {
            warn "Can't open $file: $!";
            next;
        };
        recurse_open($fh_next);
    }   
}

这会打印出来

主文件 file1.txt 在里面 主文件结束 --- 文件一,与 一行 file2.txt 一个结束 --- 文件二,其中有 一行 file3.txt 两个结束 --- 只是文件3, 没有更多的文件名。 ---

file.txt 和文件 1..3 的内容,用于测试,我希望是清楚的(由--- 分隔)。如果碰巧有多个文件名,则会跟踪文件中存在的所有文件名。

如果标题中的短语“不破坏文件句柄”表示文件句柄应该保持打开(并收集),那么只需在打开时将它们添加到数组中

open my $fh, '<', $file or die "Can't open $file: $!";
my @filehandles = ($fh);

recurse_open($fh, \@filehandles);

sub recurse_open {
    my ($fh, $handles) = @_;
    ...
    foreach my $file (@files) {
        open my $fh_next, '<', $file  or do {
            warn "Can't open $file: $!";
            next;
        };    
        push @$handles, $fh_next;
        recurse_open($fh_next, $handles);
    }
}

通常,(词法)文件句柄在超出范围时会关闭。但是,由于现在每个都被复制到在更大范围内定义的数组中,因此它们被保留,因为每个都有一个引用。


对问题中的代码进行评论。

最严重的错误是对文件句柄的含义和作用的明显误解。表达式&lt;$fh&gt; 在打开时从与文件句柄$fh 关联的文件中读取,其中&lt;&gt; 是readline 的运算符版本。见I/O Operators in perlop。

这会在文件中返回一行, 是您应该使用chomp、m// 等处理的内容,而不是$fh 本身。对于while (&lt;$fh&gt;)(条件中没有其他内容),该行被分配给special variable $_,这是Perl 中许多东西的默认设置。上面的代码利用了这一点。

接下来,您实际上并没有匹配并捕获文件名,而是仅匹配.txt。 (该匹配使用文件句柄而不是包含该行的变量,open 使用该文件句柄代替文件名,这就是上面提到的文件句柄混淆。)

然后,我认为没有必要围绕$set 跳舞,增加和减少它。由于您很好地将所有这些都归为子例程,因此只需在变量中使用文件句柄即可。所以我取消了数组。如有其他原因,请恢复。

最后:

  • 总是以use warnings; 和use strict; 启动程序。这不是什么迂腐,而是直接有助于发现错误,并执行一些非常好的做法。

  • 总是检查您的 open 电话 (open ... or ...)

  • 使用词法文件句柄 (my $fh) 而不是 glob (FH),它们要好得多。使用open的三参数版本

如果这是全部目的,您不妨将文件名传递给递归子程序并让它打开并读取文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-02
    • 2017-01-28
    相关资源
    最近更新 更多