CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
Search Posts SEARCH
Who's Online WHO'S
Log in LOG

Home: Perl Programming Help: Frequently Asked Questions:
How can I make a filehandle local to a subroutine?



Jan 26, 2001, 10:07 AM

Post #1 of 1 (2231 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:

    local *TmpHandle;

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.


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives