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

how to open a file which is present in another file recursively in perl

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!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;
          }
    }
}
1
2
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文件,然后返回(transverse a tress)在我们的例子中,file1->file2->file4->file3->file1 end程序。我不知道我的程序为什么不起作用。提前谢谢*


我的看法是:读取一个文件,如果找到文件名(由.txt判断),打开并读取这些文件名,然后递归进行。发布的代码有一些基本错误,下面讨论。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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);
    }  
}

这张照片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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的内容清楚,我希望(用---分开)。如果一个文件中有多个文件名,那么这将跟踪该文件中的所有文件名。

如果标题中的短语"不销毁文件句柄"意味着文件句柄应保持打开(和收集),那么只需在打开时将其添加到数组中即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
    }
}

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

对问题代码的注释。

最严重的错误是对filehandle是什么和做什么的明显误解。表达式<$fh>从打开时与文件句柄$fh关联的文件中读取,其中<>是readline的运算符版本。请参见Perlop中的I/O操作符。

这将返回文件中的一行,这是您应该处理的内容,包括chompm//等,而不是$fh本身。对于while (<$fh>)(条件中没有其他内容),行被分配给特殊变量$_,这在Perl中是许多事物的默认值。上面的代码利用了这一点。

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

那么,我不认为有必要在$set周围跳舞,增加和减少它。因为您很好地将所有这些都降级为子例程,所以只需在变量中使用filehandle。所以我取消了阵列。如果由于其他原因需要,请将其恢复。

最后:

  • 始终使用use warnings;use strict;启动程序。这不是什么学究,而是直接帮助捕捉错误,并强制执行一些非常好的实践。

  • 始终检查您的open呼叫(open ... or ...)

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

如果这是全部目的,您也可以将文件名传递给递归子文件,并让它打开并读取该文件。