如何在perl中以递归方式打开另一个文件中存在的文件

时间:2018-10-07 03:27:11

标签: perl recursion filehandle recursive-datastructures

递归打开文件而不会破坏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 #assume file2.txt comes before file3.txt 
file2.txt-file4.txt file3.txt 

我想打开file1.txt并在file1中打印数据,如果我发现     文件中的file2.txt打开文件以打印数据并递归     直到文件中不包含.txt文件,然后返回     (横断树)在我们的情况下file1-> file2-> file4-> file3-> file1结尾      程序。我不知道为什么我的程序无法正常工作。预先感谢*

1 个答案:

答案 0 :(得分:2)

我对这个问题的看法:读取文件,如果找到文件名(由.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);
    }   
}

此打印

main file
file1.txt is in it
end of main file
---
file one, with
a line with file2.txt
end of one
---
file two, which has
a line with file3.txt
end of two
---
Just the file3,
no more filenames.
---

我希望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);
    }
}

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


对问题代码的评论。

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

这将在文件中返回一行,并且 是您应该使用的行,使用chompm//等,而不是$fh本身。使用while (<$fh>)(条件中没有其他条件),将行分配给special variable $_,这在Perl中是默认的。上面的代码利用了这一点。

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

然后,我看不到围绕$set跳舞,增加和减少舞蹈的必要性。由于您很好地将所有这些操作都放到了子例程中,因此只需在变量中使用filehandle即可。所以我取消了阵列。如果出于其他原因需要将其恢复。

最后:

  • 始终使用use warnings;use strict;启动程序。这不是什么学问,而是直接可以帮助发现错误,并且也可以实施一些非常好的做法。

  • 始终检查您的open通话(open ... or ...

  • 使用词法文件句柄(my $fh)代替glob(FH),它们会更好。使用open

  • 的三参数版本

如果这是全部目的,则最好将文件名传递给递归子文件,并使其打开并读取文件。