You 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.
If you already have a regular symbolic filehandle like STDIN or LOGFILE, use the typeglob notation,
*FH
. This is the most efficient approach.
$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
new
method from the IO::File or IO::Handle module, store that in a scalar variable, and use it as though it were a normal filehandle:
use FileHandle; # make anon filehandle $fh = FileHandle->new(); use IO::File; # 5.004 or higher $fh = IO::File->new();
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,
*FH
. It may help you to conceptualize the asterisk as the type symbol for a filehandle. Like the little colored balls from high school chemistry that stood for atomic particles, it's not really true, but it is a convenient mental shorthand. By the time you understand where this model breaks down, you won't need it anymore.
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
new
method. This returns a filehandle you can pass to subroutines, store in arrays, and use however you would use a named filehandle's typeglob - plus more. You can also use those modules as object classes for inheritance purposes because the return values from the
new
constructor are fully fledged objects, complete with available method calls.
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
bless
it to turn it into an object. To do this, you must
bless
a
reference
to a typeglob - that's what IO::Handle does. Like typeglobs, references to typeglobs can be safely used as indirect filehandles, whether blessed or not.
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 (
"LOGFILE"
instead of
*LOGFILE
) require special finessing to work between packages, and references to typeglobs can't be usefully returned from functions.
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
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, 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, 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
readline
to read a record just as
<FH>
does. Given the preceding initialization of
@fd
, this would work:
$got = readline($fd[0]);
The
open
function in
perlfunc
(1) and in
Chapter 3
of
Programming Perl
;
Recipe 7.1
; the documentation with the standard FileHandle module (also in
Chapter 7
of
Programming Perl
); the
"Typeglobs and Filehandles"
section of
Chapter 2
of
Programming Perl
and
Chapter 2
of
Programming Perl
Copyright © 2001 O'Reilly & Associates. All rights reserved.