![]() |
|
Pathologically Eclectic Rubbish Lister | |
PerlMonks |
How can I use a filehandle indirectly?by faq_monk (Initiate) |
on Oct 08, 1999 at 00:23 UTC ( #650=perlfaq nodetype: print w/replies, xml ) | Need Help?? |
Current Perl documentation can be found at perldoc.perl.org. Here is our local, out-dated (pre-5.6) version: An indirect filehandle is using something other than a symbol in a place that a filehandle is expected. Here are ways to get those:
$fh = SOME_FH; # bareword is strict-subs hostile $fh = "SOME_FH"; # strict-refs hostile; same package only $fh = *SOME_FH; # typeglob $fh = \*SOME_FH; # ref to typeglob (bless-able) $fh = *SOME_FH{IO}; # blessed IO::Handle from *SOME_FH typeglob
Or to use the
use FileHandle; $fh = FileHandle->new();
use IO::Handle; # 5.004 or higher $fh = IO::Handle->new();
Then use any of those as you would a normal filehandle. Anywhere that Perl
is expecting a filehandle, an indirect filehandle may be used instead. An
indirect filehandle is just a scalar variable that contains a filehandle.
Functions like print, open, seek, or the functions or the
($ifh, $ofh, $efh) = (*STDIN, *STDOUT, *STDERR); print $ofh "Type it: "; $got = <$ifh> print $efh "What was that: $got"; Of you're passing a filehandle to a function, you can write the function in two ways:
sub accept_fh { my $fh = shift; print $fh "Sending to indirect filehandle\n"; } Or it can localize a typeglob and use the filehandle directly:
sub accept_fh { local *FH = shift; print FH "Sending to localized filehandle\n"; } Both styles work with either objects or typeglobs of real filehandles. (They might also work with strings under some circumstances, but this is risky.)
accept_fh(*STDOUT); accept_fh($handle); In the examples above, we assigned the filehandle to a scalar variable before using it. That is because only simple scalar variables, not expressions or subscripts into hashes or arrays, can be used with built-ins like print, printf, or the diamond operator. These are illegal and won't even compile:
@fd = (*STDIN, *STDOUT, *STDERR); print $fd[1] "Type it: "; # WRONG $got = <$fd[0]> # WRONG print $fd[2] "What was that: $got"; # WRONG With print and printf, you get around this by using a block and an expression where you would place the filehandle:
print { $fd[1] } "funny stuff\n"; printf { $fd[1] } "Pity the poor %x.\n", 3_735_928_559; # Pity the poor deadbeef. That block is a proper block like any other, so you can put more complicated code there. This sends the message out to one of two places:
$ok = -x "/bin/cat"; print { $ok ? $fd[1] : $fd[2] } "cat stat $ok\n"; print { $fd[ 1+ ($ok || 0) ] } "cat stat $ok\n";
This approach of treating print and printf like object methods calls doesn't work for the diamond operator. That's
because it's a real operator, not just a function with a comma-less
argument. Assuming you've been storing typeglobs in your structure as we
did above, you can use the built-in function named
$got = readline($fd[0]); Let it be noted that the flakiness of indirect filehandles is not related to whether they're strings, typeglobs, objects, or anything else. It's the syntax of the fundamental operators. Playing the object game doesn't help you at all here.
|
|