如何读取作为数组元素的Perl文件句柄?
我很快草草记下了一个Perl脚本,该脚本将几个文件平均起来,只包含一列数字。它涉及从文件句柄数组中读取。以下是脚本:如何读取作为数组元素的Perl文件句柄?,perl,arrays,filehandle,Perl,Arrays,Filehandle,我很快草草记下了一个Perl脚本,该脚本将几个文件平均起来,只包含一列数字。它涉及从文件句柄数组中读取。以下是脚本: #!/usr/local/bin/perl use strict; use warnings; use Symbol; die "Usage: $0 file1 [file2 ...]\n" unless scalar(@ARGV); my @fhs; foreach(@ARGV){ my $fh = gensym; open $fh, $_ or di
#!/usr/local/bin/perl
use strict;
use warnings;
use Symbol;
die "Usage: $0 file1 [file2 ...]\n" unless scalar(@ARGV);
my @fhs;
foreach(@ARGV){
my $fh = gensym;
open $fh, $_ or die "Unable to open \"$_\"";
push(@fhs, $fh);
}
while (scalar(@fhs)){
my ($result, $n, $a, $i) = (0,0,0,0);
while ($i <= $#fhs){
if ($a = <$fhs[$i]>){
$result += $a;
$n++;
$i++;
}
else{
$fhs[$i]->close;
splice(@fhs,$i,1);
}
}
if ($n){ print $result/$n . "\n"; }
}
#/usr/local/bin/perl
严格使用;
使用警告;
使用符号;
die“用法:$0 file1[file2…]\n”,除非标量(@ARGV);
我的@fhs;
foreach(@ARGV){
my$fh=gensym;
打开$fh、$或死“无法打开\“$”;
推送(@fhs,$fh);
}
while(标量(@fhs)){
我的($result,$n,$a,$i)=(0,0,0,0);
当我关门的时候;
拼接(@fhs,$i,1);
}
}
如果($n){print$result/$n.“\n”;}
}
这不起作用。如果我调试脚本,在初始化@fhs之后,它看起来如下所示:
DB<1> x @fhs
0 GLOB(0x10443d80)
-> *Symbol::GEN0
FileHandle({*Symbol::GEN0}) => fileno(6)
1 GLOB(0x10443e60)
-> *Symbol::GEN1
FileHandle({*Symbol::GEN1}) => fileno(7)
DB x@fhs
0全局(0x10443d80)
->*符号::GEN0
FileHandle({*Symbol::GEN0})=>fileno(6)
1全局(0x10443e60)
->*符号::GEN1
FileHandle({*Symbol::GEN1})=>fileno(7)
到目前为止,还不错。但在我尝试读取文件的部分失败:
DB<3> x $fhs[$i]
0 GLOB(0x10443d80)
-> *Symbol::GEN0
FileHandle({*Symbol::GEN0}) => fileno(6)
DB<4> x $a
0 'GLOB(0x10443d80)'
DB x$fhs[$i]
0全局(0x10443d80)
->*符号::GEN0
FileHandle({*Symbol::GEN0})=>fileno(6)
DB x$a
0'全局(0x10443d80)'
$a是用这个字符串填充的,而不是从全局读取的内容。我做错了什么?您只能在
中使用一个简单的标量变量来读取文件句柄。
可以工作。
不从文件句柄读取;它实际上相当于glob($foo[0])
。您必须使用readline
内置的临时变量,或者使用and和OO表示法
$text = readline($foo[0]);
# or
my $fh = $foo[0]; $text = <$fh>;
# or
$text = $foo[0]->getline; # If using IO::File
$text=readline($foo[0]);
#或
my$fh=$foo[0];$text=;
#或
$text=$foo[0]->getline;#如果使用IO::File
如果没有从循环内的数组中删除元素,可以通过将while
循环更改为foreach
循环来轻松使用临时变量
就我个人而言,我认为使用
gensym
创建文件句柄是一个难看的黑客行为。您应该使用IO::File,或者将一个未定义的变量传递给open
(这至少需要Perl 5.6.0,但现在已经快10年了)。(只需说my$fh;
而不是my$fh=gensym;
,当您调用open
时,Perl将自动创建一个新的文件句柄并将其存储在$fh
中)我理解您的逻辑有困难。是否要读取几个只包含数字(每行一个数字)的文件然后打印平均值
use strict;
use warnings;
my @fh;
foreach my $f (@ARGV) {
open(my $fh, '<', $f) or die "Cannot open $f: $!";
push @fh, $fh;
}
foreach my $fh (@fh) {
my ($sum, $n) = (0, 0);
while (<$fh>) {
$sum += $_;
$n++;
}
print "$sum / $n: ", $sum / $n, "\n" if $n;
}
使用严格;
使用警告;
我的@fh;
每个我的$f(@ARGV){
打开(我的$fh,“如果你愿意使用一些魔法,你可以非常简单地做到这一点:
use strict;
use warnings;
die "Usage: $0 file1 [file2 ...]\n" unless @ARGV;
my $sum = 0;
# The current filehandle is aliased to ARGV
while (<>) {
$sum += $_;
}
continue {
# We have finished a file:
if( eof ARGV ) {
# $. is the current line number.
print $sum/$. , "\n" if $.;
$sum = 0;
# Closing ARGV resets $. because ARGV is
# implicitly reopened for the next file.
close ARGV;
}
}
使用严格;
使用警告;
die“用法:$0 file1[file2…]\n”,除非@ARGV;
我的$sum=0;
#当前文件句柄的别名为ARGV
而(){
$sum+=$\ux;
}
继续{
#我们已完成一个文件:
如果(eof ARGV){
#$。是当前行号。
打印$sum/$,如果$,则为“\n”。;
$sum=0;
#关闭ARGV将重置$。因为ARGV是
#隐式地为下一个文件重新打开。
关闭ARGV;
}
}
除非您使用的是非常旧的perl,否则没有必要乱搞gensym
。IIRC、perl 5.6和更新版本对正常的词法句柄很满意:open my$fh,似乎是for
循环对您更有效,因为您可以实际使用标准的读取(迭代)操作符
for my $fh ( @fhs ) {
while ( defined( my $line = <$fh> )) {
# since we're reading integers we test for *defined*
# so we don't close the file on '0'
#...
}
close $fh;
}
我的$fh(@fhs){
while(已定义(my$line=)){
#因为我们读取的是整数,所以我们测试的是*定义的*
#因此我们不关闭“0”上的文件
#...
}
收盘价$fh;
}
看起来你根本不想缩短循环。因此,while
似乎是一个错误的循环习惯用法。我会给你1000个停止使用p的代表。问题是文件不能保证有相同的行数。或者等同于
,它被拼写为readline HANDLE
ike.但是,$count
有什么用呢?另外,除非在标量上下文中隐式使用@ARGV
,我不会把它算作魔法,我也会这样写:)好的方面。除非标量是粘贴OP代码时留下的。$计数是在我意识到我可以使用行号之前留下的。