From: Tom Christiansen <
[email protected]>
Subject: Re: Array of File Handles?
Cc:
[email protected] (Graham Randall)
Reply-to:
[email protected] (Tom Christiansen)
Organization: Perl Consulting and Training
Newsgroups: comp.lang.perl.misc
Summary:
Keywords:
Forwarded: Sat, 07 Oct 95 17:24:18 MDT
Todd Miller <
[email protected]>
[courtesy cc of this posting sent to cited author via email]
In comp.lang.perl.misc,
[email protected] (Graham Randall) writes:
:
:
:[ Disclaimer:
: I imagine this would be a FAQ, but I didn't see it anywhere in there.]
Yes, it's a FAQ, but it's not there. I'm going to reuse some of my
recent material, so some of you out there may have already read this.
:I have a bunch of statistics I need to output into twelve different
:files based on certain criteria. I would like to put the output routines
:in a big loop and then index the array to get the appropriate file
:handle. Unfortunately, two problems stand in my way.
:
:1) When I try to print to a file handle in the array, the perl
: compiler fails because it says it found a string where it
: expected an operator. Example,
:
: print ${files[$i]} "This is a sample.\n";
:
: However, if I rewrite this as:
:
: $f = $files[$i];
: print $f "This is a sample.\n";
:
: No error is generated.
:
The proper definition of printf is
printf fh_obj LIST
just as print's is
print fh_obj LIST
where "fh_obj" is optional, but if present, *MUST* be
1) a bareword
2) a scalar containing a bareword or glob reference or
FileHandle object reference
3) a code block returning the same as #2
Thus you may do
print "I have: ", ccount(), "bunnies.\n";
print STDOUT "I have: ", ccount(), "bunnies.\n";
$var = 'module::FH';
print $var "I have: ", ccount(), "bunnies.\n";
$var = \*FH;
print $var "I have: ", ccount(), "bunnies.\n";
print { $ok ? 'STDOUT' : 'STDERR' } "I have: ", ccount(), "bunnies.\n";
$fh[$i] = \*FH;
print { $fh[$i] } "I have: ", ccount(), "bunnies.\n";
But you may *NOT* do:
print $fh[$i] "I have: ", ccount(), "bunnies.\n"; # WRONG
nor
print $fh[$i], "I have: ", ccount(), "bunnies.\n"; # WRONG
I don't advise that people use parens at all. If you do, you get code
that looks like this
print(STDERR "I have: ", ccount(), "bunnies.\n"); # CONFUSING
I very much dislike parens in front of an object, because then you're
tempted to write:
print(STDERR, "I have: ", ccount(), "bunnies.\n"); # WRONG
You might of course do this if you'd "use FileHandle" in your code:
STDERR->print("I have: ", ccount(), "bunnies.\n");
or even
$fh[$i]->print("I have: ", ccount(), "bunnies.\n");
To avoid those confusions -- or introduce new ones. :-)
:2) When I try to print to a file handle in the array, the perl
: interpreter tells me that I cannot print to a closed file
: handle. This is because I initialize my array in the following
: manner.
:
: for ($i=0; $i<$MAX_FILES; $i++) {
: open(INPUT, ">foo");
: $files[$i] = INPUT;
: }
:
: Perl closes the file handle INPUT on each call to open, and
: apparently, $files[$i] = INPUT doesn't copy the file handle.
: Statically, initializing the array is inflexible and lacks
: elegance.
:
:Can anyone help me? This should be something you can do in Perl 5.001m.
Ok, now you need something else. Here's a simple solution
for ($i=0; $i<$MAX_FILES; $i++) {
my $fh = FileHandle->new();
open($fh, ">foo");
$files[$i] = $fh;
}
Now, what you need a decent definition for FileHandle->new, and we
don't have one. Here's one that will work. I still would like to do
a lot more to it, but I'm not really ready to override open() yet
to do so.
{
use strict;
require FileHandle; # make sure real one is loaded
package FileHandle;
########################################
### FileHandle class CONSTRUCTOR
########################################
#
# This space intentionally left blank.
#
########################################
########################################
### FileHandle class DESTRUCTOR
########################################
#
# sub END {} # nothing to do, so let's not have one
#
#######################################
########################################
## FileHandle instance CONSTRUCTOR
########################################
sub new {
my $self = shift;
my $class = ref($self) || $self; # for inheritance
return bless(&_genfh, $class);
}
########################################
## FileHandle instance DESTRUCTOR
########################################
sub DESTROY {
my $self = shift;
if (defined fileno $self) {
close $self;
}
}
########################################
# internal only - black black magic
########################################
sub _genfh { # YANETUT :-(
no strict 'refs';
local *{'FileHandle::DEMI_ANON_GLOB'};
return \delete $FileHandle::{DEMI_ANON_GLOB};
}
1;
}
This needs to be put crafted into a Far More Than Everything You Ever
Wanted to Know about FileHandles document. (Actually, I'm hoping to get
it into FileHandle.pm for 5.002, and the pods.) I need to finish the PDSC
first, but then maybe I'll get a round tuit (I've noticed Larry needs some
himself a lot lately.)
--tom