当我运行时:
open FP, ">xyz";
my $file = *FP;
printf $file "first\n";
$file = *STDOUT;
printf $file "second\n";
open $file, ">abc";
print $file "third\n";
print STDOUT "fourth\n";
print FP "fifth\n";
“第四次”打印不会转到STDOUT,而是转到“abc”。
STDOUT与FP的不同之处在于行为符合预期。
我做错了什么?我不理解的是什么?
答案 0 :(得分:11)
嗯,对于初学者来说,你错误地使用'开放'。
open my $fp , '>', 'xyz' ;
是推荐的语法。
你强烈建议你使用裸露的'FP',因为它不是词汇。
其次,你将文件指针重新打开为新事物。这不是很好的做法,它应该不是问题,但它只是一个坏主意。你应该关闭文件指针或让它超出范围(通过词法)。
第三,'* STDOUT'是一个参考。
my $fh = *STDOUT;
print "$fh\n"; #prints '*main::STDOUT';
所以当你这样做时:
open $fh, '>abc';
你正在做什么
open *STDOUT, '>abc';
如果你之后立即做
print "$fh\n";
你会注意到它仍会打印*main::STDOUT
;
一些有趣的代码片段清除了这一点:
my $fh = *STDOUT;
open $fh, '<', "foo.txt";
print $fh "hello";
# Filehandle STDOUT opened only for input at (eval 288) line 6.
my $fh = *STDIN;
open $fh, '<', "foo.txt";
print <>;
# contents of foo.txt here
以下是推荐使用open的方法:
sub foo {
my $fh;
open $fh , '<', 'file.txt' or Carp::croak('Cannot Open File.txt');
# do stuff with $fh;
close $fh or Carp::carp('Something annoying in close :S ');
}
请注意,如果省略关闭,只要$ fh超出可见度,文件就会关闭。
答案 1 :(得分:6)
如果我理解你要做什么,我想你想使用select
。它允许您轻松切换文件句柄。您还应该使用更现代的open形式(3个参数,词法文件句柄和错误检查)。请参阅perldoc perlopentut
。
#!/usr/bin/env perl
use strict;
use warnings;
open my $fh, '>', 'abc' or die "Can't open 'abc': $!";
open my $fh2, '>', 'def' or die "Can't open 'def': $!";
open my $fh3, '>', 'xyz' or die "Can't open 'xyz': $!";
select $fh;
print "First\n";
# Later
select $fh2;
print "Second\n";
# Later
select $fh3;
print "Third\n";
# Later
select STDOUT;
print "Fourth\n";
答案 2 :(得分:4)
您需要保存STDOUT才能恢复它。这来自open的... perldoc:
这是一个使用各种方法保存,重定向和恢复STDOUT和STDERR的脚本:
#!/usr/bin/perl
open my $oldout, ">&STDOUT" or die "Can't dup STDOUT: $!";
open OLDERR, ">&", \*STDERR or die "Can't dup STDERR: $!";
open STDOUT, '>', "foo.out" or die "Can't redirect STDOUT: $!";
open STDERR, ">&STDOUT" or die "Can't dup STDOUT: $!";
select STDERR; $| = 1; # make unbuffered
select STDOUT; $| = 1; # make unbuffered
print STDOUT "stdout 1\n"; # this works for
print STDERR "stderr 1\n"; # subprocesses too
open STDOUT, ">&", $oldout or die "Can't dup \$oldout: $!";
open STDERR, ">&OLDERR" or die "Can't dup OLDERR: $!";
print STDOUT "stdout 2\n";
print STDERR "stderr 2\n";
查看“或死”部分。你应该总是测试一个开放的错误...
答案 3 :(得分:3)
本地化STDOUT。然后,您可以在有限的动态范围内对其进行别名。离开该范围后,STDOUT将恢复正常。
use strict;
use warnings;
print_stuff('Normal STDOUT');
{ local *STDOUT;
open( STDOUT, '>', 'out' )
or die "Can't redirect STDOUT: $!";
local $| = 1; # Unbuffer handle.
# Do this AFTER redirecting STDOUT.
print_stuff('Aliased to out');
sleep 10;
}
print_stuff('Back to normal STDOUT');
sub print_stuff {
print join "\n", @_, '';
}
答案 4 :(得分:1)
当您执行打开$ file,“&gt; abc”时,您从根本上操作的是STDOUT的文件描述符,您现在已将其重新打开到另一个目标。也就是说,当你执行打开时,你的两个别名都在一个被重新利用的底层资源上运行,而不管用于引用它的别名。
答案 5 :(得分:0)
如果我将在短时间内使用文件句柄,我会把它放在一个匿名块中。这会自动限制任何非全局变量的范围。
{
open my $fh, '>', 'abc';
print $fh "assorted data";
close $fh;
}
作为额外的好处,您甚至不需要拥有“close $fh;
”行,因为当变量超出范围时它会自动关闭。
如果要使用此技术,则应始终本地化在代码块内修改的任何全局变量。
{
local *FH;
open FH, '>', 'abc';
print FH "assorted data";
close FH;
}