递归打开文件而不会破坏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结尾 程序。我不知道为什么我的程序无法正常工作。预先感谢*
答案 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。
这将在文件中返回一行,并且 是您应该使用的行,使用chomp
,m//
等,而不是$fh
本身。使用while (<$fh>)
(条件中没有其他条件),将行分配给special variable $_
,这在Perl中是默认的。上面的代码利用了这一点。
接下来,您实际上并不匹配并捕获文件名,而仅匹配.txt
。 (该匹配使用文件句柄而不是包含该行的变量,open
使用该文件句柄代替文件名,这是上面提到的文件句柄的混淆。)
然后,我看不到围绕$set
跳舞,增加和减少舞蹈的必要性。由于您很好地将所有这些操作都放到了子例程中,因此只需在变量中使用filehandle即可。所以我取消了阵列。如果出于其他原因需要将其恢复。
最后:
始终使用use warnings;
和use strict;
启动程序。这不是什么学问,而是直接可以帮助发现错误,并且也可以实施一些非常好的做法。
始终检查您的open
通话(open ... or ...
)
使用词法文件句柄(my $fh
)代替glob(FH
),它们会更好。使用open
如果这是全部目的,则最好将文件名传递给递归子文件,并使其打开并读取文件。