File handling with subroutines and references

E

Eric Martin

I am processing multiple files and am trying to create routines that
will efficiently read/write files. I am using variable names for the
FILEHANDLE to prevent any conflicts during processing (Is this a good
practice or is there a *better* way?).

use strict; use warnings;
no strict 'refs';
use Fcntl qw:)DEFAULT :flock);

sub file_open {
my ($fh, $file, $mode) = @_;
open($fh, "$mode $file") || die("Cannot open $file: $!");
flock($fh, LOCK_EX);
return \*$fh;
}

sub file_close {
my $fh = shift;
close($fh);
}

my $file = "data.txt";
my $fh = file_open("TEST_OUT", $file, '+<');
my $out = file_open("TEST_IN", "data_out.txt", '+>');
while (<$fh>) {
# process data
# ...
print $out $_;
}
file_close($out);
file_close($fh);

__END__

I tried:
sub file_open {
my ($fh, $file, $mode) = @_;
my $filehandle = do { local *$fh }; # <-- ADDED
open($filehandle, "$mode $file") || die("Cannot open $file: $!");
flock($filehandle, LOCK_EX);
return \*$filehandle;
}

which I saw in an example. I've seen it used for file "slurping", but I
am not sure if it is something I should use. My understanding is that
it is used to make the FILEHANDLE local, but in the context that I am
using, it doesn't seem necessary.

I know there are modules out there to use, but I am not using them
because I need the code to work with the standard 5.004 Perl install.

I'm looking for any code/design comments. Anything that I'm not doing
or that I should be doing?

Thanks,
Eric
 
X

xhoster

Eric Martin said:
I am processing multiple files and am trying to create routines that
will efficiently read/write files. I am using variable names for the
FILEHANDLE to prevent any conflicts during processing
(Is this a good
practice or is there a *better* way?).

use strict; use warnings;
no strict 'refs';

Why that? Is it necessary for what you are doing here?
use Fcntl qw:)DEFAULT :flock);

sub file_open {
my ($fh, $file, $mode) = @_;
open($fh, "$mode $file") || die("Cannot open $file: $!");
flock($fh, LOCK_EX);

You should check the success (return value) of flock:

flock($fh, LOCK_EX) or die "$file: $!";
return \*$fh;
}

sub file_close {
my $fh = shift;
close($fh);

# Not as important to check as open or flock,
# but may as well do it anyway!
close ($fh) or die $!;
I know there are modules out there to use, but I am not using them
because I need the code to work with the standard 5.004 Perl install.

Ah, I had started writing a lot more comments until I noticed this part. I
no longer remember all the pitfalls from the bad old days of 5.004, so I'll
just shut up now.

Xho
 
E

Eric Martin

Why that? Is it necessary for what you are doing here?

Are you asking about the no strict 'refs'?
Not using it gives:
"Can't use string ("TEST_OUT") as a symbol ref while "strict refs" in
use at ..."
You should check the success (return value) of flock:

flock($fh, LOCK_EX) or die "$file: $!";

True.


# Not as important to check as open or flock,
# but may as well do it anyway!
close ($fh) or die $!;

True again. =)
Ah, I had started writing a lot more comments until I noticed this part. I
no longer remember all the pitfalls from the bad old days of 5.004, so I'll
just shut up now.

LOL. My program will be used on a variety of OS/Web server/Perl servers,
so I just want to make the code as backwards compatible as possible.

I was hoping that people with more IO familiarity could check the
efficiency/scalability of the code.

Thanks,
Eric
 
M

Manni Heumann

Eric said:
I am using variable names for the
FILEHANDLE to prevent any conflicts during processing (Is this a good
practice or is there a *better* way?).

IMHO, this is a very good practice. But you are using it in a strange way.
sub file_open {
my ($fh, $file, $mode) = @_;
open($fh, "$mode $file") || die("Cannot open $file: $!");
flock($fh, LOCK_EX);
return \*$fh;
} ....

my $file = "data.txt";
my $fh = file_open("TEST_OUT", $file, '+<');

Get rid of that first argument to the function call. Simply call the function
with the file name and the desired open mode, create the file handle in the
subroutine and then return it:

sub file_open {
my ( $name, $mode ) = @_;
open my $handle, "$mode $name";
return $handle;
}
 
T

Tad McClellan

Eric Martin said:
Are you asking about the no strict 'refs'?
Not using it gives:
"Can't use string ("TEST_OUT") as a symbol ref while "strict refs" in
use at ..."


When your car is making a funny noise, you count it as "fixed"
after turning up the volume on your radio?

Masking bugs is not the same as fixing bugs.
 
B

Brian McCauley

There is no conflict if two anonymous file handles have the same name.
(If you'll excuse the oxymoron).
Are you asking about the no strict 'refs'?
Not using it gives:
"Can't use string ("TEST_OUT") as a symbol ref while "strict refs" in
use at ..."

You should always disable strictures in the smallest applicable scope.

my $fh = "TEST_OUT";
my $filehandle = do { no strict 'refs'; local *$fh };

$filehandle now contains an anonymous file handle that _thinks_ its
name is TEST_OUT.

If you execute the same code again you'll get _another_ anonymous file
handle that also thinks its name is TEST_OUT.

For most purposes it doesn't matter what an anonymous file handle
thinks its name is. (Occasionally it will be displayed in debugging
info but that's about all).

So people usually just write something like.

my $filehandle = do { local *FH };

Actually I prefer to use a GLOBref rather than a GLOB. The exact
semantics of scalar variables that happen to hold GLOBs are just too
weird.

my $filehandle = \do { local *FH };


That said... why are you using such an old Perl. All this is a lot
simpler from 5.6.1 onwards where open() et al autovivify.
 
E

Eric Martin

Tad said:
When your car is making a funny noise, you count it as "fixed"
after turning up the volume on your radio?

Thanks for the analogy, but I don't think it really helps me with my
question.
Masking bugs is not the same as fixing bugs.

I'm not sure if you read my question...I wanted to use variables as
filehandle names. I took a shot at doing it and obviously I felt I
needed advice, or I wouldn't have asked the question.

I found the suggestion to use no strict 'refs' on a website talking
about passing a scalar to use as a filehandle name. So...I appreciate
you taking the time to respond, I just wish it was more to steer me in
the right direction as opposed to just telling me it's wrong.

Thanks,
Eric
 
E

Eric Martin

Manni said:
IMHO, this is a very good practice. But you are using it in a strange way.

Fair enough =)
Get rid of that first argument to the function call. Simply call the function
with the file name and the desired open mode, create the file handle in the
subroutine and then return it:

sub file_open {
my ( $name, $mode ) = @_;
open my $handle, "$mode $name";
return $handle;
}

Makes sense...thanks for the suggestions.

-Eric
 
P

Paul Lalli

Eric said:
Thanks for the analogy, but I don't think it really helps me with my
question.

That's because your question is faulty.
I'm not sure if you read my question...I wanted to use variables as
filehandle names.

*Why*? I've read this thread three or four times, and I have yet to
figure out *why* you think you need to store a "name" of a filehandle
variable in another variable. What makes you think this is necessary?
If you want a file handle reference, just make a reference. It does
not need a name of any kind.

See also: perldoc -q "variable name"

Paul Lalli
 
E

Eric Schwartz

Eric Martin said:
Makes sense...thanks for the suggestions.

I'm at least 90% sure that syntax, while much better than what you
were using, doesn't work under 5.004, which you specified. Of course,
I don't happen to have an 8-year-old copy of perl to test that with,
but I'm reasonably positive it worked as of 5.6 or so.

-=Eric
 
E

Eric Martin

Tad said:
Why do you need to use a perl that is over 8 years old?

*I* don't need to, but the people using the program might. My options
are to code to work with 5.004, or require a more recent version of
Perl. I'll evaluate the latter.

Thanks,
Eric
 
E

Eric Martin

Brian said:
There is no conflict if two anonymous file handles have the same name.
(If you'll excuse the oxymoron).

Good to know, thanks.
You should always disable strictures in the smallest applicable scope.

my $fh = "TEST_OUT";
my $filehandle = do { no strict 'refs'; local *$fh };

$filehandle now contains an anonymous file handle that _thinks_ its
name is TEST_OUT.

If you execute the same code again you'll get _another_ anonymous file
handle that also thinks its name is TEST_OUT.

For most purposes it doesn't matter what an anonymous file handle
thinks its name is. (Occasionally it will be displayed in debugging
info but that's about all).

So people usually just write something like.

my $filehandle = do { local *FH };

Actually I prefer to use a GLOBref rather than a GLOB. The exact
semantics of scalar variables that happen to hold GLOBs are just too
weird.

my $filehandle = \do { local *FH };

Thanks for all of the suggestions.
That said... why are you using such an old Perl. All this is a lot
simpler from 5.6.1 onwards where open() et al autovivify.

I'll look into requiring a more recent version.

Thanks,
Eric
 
E

Eric Martin

Paul said:
That's because your question is faulty.

How? I asked to question in order to determine if what I was trying to
do was faulty. Does that make the question or the approach faulty?
*Why*? I've read this thread three or four times, and I have yet to
figure out *why* you think you need to store a "name" of a filehandle
variable in another variable. What makes you think this is necessary?
If you want a file handle reference, just make a reference. It does
not need a name of any kind.

Because I obviously didn't completely understand filehandles and their
names. With some helpful suggestions, I have been able to understand
what is going on and that I don't need to *name* the filehandles.
See also: perldoc -q "variable name"

Thanks.

-Eric
 
P

Paul Lalli

Eric said:
How? I asked to question in order to determine if what I was trying to
do was faulty. Does that make the question or the approach faulty?

The question was faulty because you were not asking for help with your
*actual* goal. You were asking for help with something you wanted to
do to achieve your goal. This is traditionally known as the XY
problem. You want to do X, you think you need to do Y to do X, so you
ask for help with Y instead of with X.
Because I obviously didn't completely understand filehandles and their
names. With some helpful suggestions, I have been able to understand
what is going on and that I don't need to *name* the filehandles.

Right. You didn't understand filehandles, and made several assumptions
about them. Next time, don't make the assumptions, ask the questions
straight out.

Paul Lalli
 
B

Brian McCauley

Manni said:
open my $handle, "$mode $name";

That makes no sense.

Autovivifcation of filehandles feature of open() was introduced _after_
the removal misfeature that required the mode and name arguments to be
combined into a single string.

If you can assume that open() supports autovivifcation then you can
assume it support mode and name as separate aruments.
 
E

Eric Martin

Brian said:
That makes no sense.

Autovivifcation of filehandles feature of open() was introduced _after_
the removal misfeature that required the mode and name arguments to be
combined into a single string.

If you can assume that open() supports autovivifcation then you can
assume it support mode and name as separate aruments.

Hmm...according to the perl561delta, it looks like autovivification and
the 3 argument open() were added in 5.6.1:
http://perldoc.perl.org/perl561delta.html#File-and-directory-handles-can-be-autovivified

Either way, your second statement would be correct =)

-Eric
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,227
Latest member
Daniella65

Latest Threads

Top