7.16. Storing Filehandles in VariablesProblemYou want to use a filehandle like a normal variable so you can pass it to or return it from a function, store it in a data structure, and so on. Solution
If you already have a regular symbolic filehandle like STDIN or LOGFILE, use the typeglob notation, $variable = *FILEHANDLE; # save in variable subroutine(*FILEHANDLE); # or pass directly sub subroutine { my $fh = shift; print $fh "Hello, filehandle!\n"; }
If you want anonymous filehandles, see the
return_fh
function below, or use the use FileHandle; # make anon filehandle $fh = FileHandle->new(); use IO::File; # 5.004 or higher $fh = IO::File->new(); Discussion
You have many choices for passing filehandles into a subroutine or storing them in a data structure. The simplest and fastest way is through the
typeglob notation, That works cleanly for simple things, but what if you wanted to make an array of filehandles whose names you didn't know? As shown in Chapter 11, References and Records , generating anonymous arrays, hashes, and even functions on the fly can prove extremely convenient. It would be nice to be able to do the same with filehandles. That's where the IO modules come in.
You can generate an anonymous handle with the IO::Handle or IO::File module's You can use these as indirect filehandles, which saves you the trouble of thinking up filehandle names. Instead, you think up names to store the anonymous filehandles in.
To capture the typeglob from a named filehandle, prefix it with $fh_a = IO::File->new("< /etc/motd") or die "open /etc/motd: $!"; $fh_b = *STDIN; some_sub($fh_a, $fh_b);
This isn't the only way, but it is the simplest and most convenient. Its only limitation is that you can't To create and return a new filehandle from a function, do this: sub return_fh { # make anon filehandle local *FH; # must be local, not my # now open it if you want to, then... return *FH; } $handle = return_fh(); A subroutine accepting a filehandle argument can either store the argument into a (preferably lexical) variable and use that as an indirect filehandle: 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 IO::Handle objects or typeglobs of real filehandles: accept_fh(*STDOUT); accept_fh($handle);
Perl accepts many things as indirect
filehandles (strings, typeglobs, and references to typeglobs), but unless you pass typeglobs or IO::Handle objects you may run into trouble. Strings (
In the preceding examples, 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 @fd = (*STDIN, *STDOUT, *STDERR); print $fd[1] "Type it: "; # WRONG $got = <$fd[0]> # WRONG print $fd[2] "What was that: $got"; # WRONG
With
print { $fd[1] } "funny stuff\n";
printf { $fd[1] } "Pity the poor %x.\n", 3_735_928_559;
That block is a proper block, 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 $got = readline($fd[0]); See Also
The |
|