
Jasmine
Administrator
Jan 26, 2001, 10:07 AM
Post #1 of 1
(3744 views)
|
How can I make a filehandle local to a subroutine?
|
Can't Post
|
|
(From the Perl FAQ) How can I make a filehandle local to a subroutine? How do I pass filehandles between subroutines? How do I make an array of filehandles? The fastest, simplest, and most direct way is to localize the typeglob of the filehandle in question: Typeglobs are fast (especially compared with the alternatives) and reasonably easy to use, but they also have one subtle drawback. If you had, for example, a function named TmpHandle(), or a variable named %TmpHandle, you just hid it from yourself. sub findme { local *HostFile; open(HostFile, "</etc/hosts") or die "no /etc/hosts: $!"; local $_; # <- VERY IMPORTANT while (<HostFile>) { print if /\b127\.(0\.0\.)?1\b/; } # *HostFile automatically closes/disappears here } Here's how to use this in a loop to open and store a bunch of filehandles. We'll use as values of the hash an ordered pair to make it easy to sort the hash in insertion order. @names = qw(motd termcap passwd hosts); my $i = 0; foreach $filename (@names) { local *FH; open(FH, "/etc/$filename") || die "$filename: $!"; $file{$filename} = [ $i++, *FH ]; } # Using the filehandles in the array foreach $name (sort { $file{$a}[0] <=> $file{$b}[0] } keys %file) { my $fh = $file{$name}[1]; my $line = <$fh>; print "$name $. $line"; } For passing filehandles to functions, the easiest way is to prefer them with a star, as in func(*STDIN). See Passing Filehandles for details. If you want to create many, anonymous handles, you should check out the Symbol, FileHandle, or IO::Handle (etc.) modules. Here's the equivalent code with Symbol::gensym, which is reasonably light-weight: foreach $filename (@names) { use Symbol; my $fh = gensym(); open($fh, "/etc/$filename") || die "open /etc/$filename: $!"; $file{$filename} = [ $i++, $fh ]; } Or here using the semi-object-oriented FileHandle, which certainly isn't light-weight: use FileHandle; foreach $filename (@names) { my $fh = FileHandle->new("/etc/$filename") or die "$filename: $!"; $file{$filename} = [ $i++, $fh ]; } Please understand that whether the filehandle happens to be a (probably localized) typeglob or an anonymous handle from one of the modules, in no way affects the bizarre rules for managing indirect handles. See the next question.
|