Re: Scoping question - will file handle be closed?
by toolic (Bishop) on Jul 14, 2015 at 19:33 UTC
|
From open:
The filehandle will be closed when its reference count reaches zero. If it is a lexically scoped variable declared with my, that usually means the end of the enclosing scope. However, this automatic close does not check for errors, so it is better to explicitly close filehandles, especially those used for writing
| [reply] |
|
|
| [reply] |
|
|
You're right, I also don't know. Most of the time, I do explicitly close my file handles, even if it is not necessary (at least, it is self-documenting), but I don't ever check whether closing the file was successful. Quite often, I close a bunch of files in one line such as:
close $_ for qw/$IN1 $IN2 $OUT1 $OUT2/;
(Except that this is just an example, I am usually trying to give more useful names to my file handles.) | [reply] [d/l] |
|
|
Warn the user that there's something wrong. The most likely cause is Perl failed to write the data to disk.
| [reply] |
|
|
|
|
|
|
|
|
|
|
Filehandles are global, irrespective of the scope in which they are referenced. To say the filehandle closes when the reference count reaches zero is incorrect. Try it...
use strict;
use warnings;
if (1) {
my $fh = \*FH;
open $fh, 'ls /usr |';
}
$_ = <FH>;
warn $_;
After the closing braces, there is nothing left in scope. In spite of that the filehandle FH remains open and $_ will be populated with the first file in /usr.
Update: I didn't realise I was arguing against perldoc. LOL, oh well, I can't retract what I know to be true!
| [reply] [d/l] |
|
|
use strict;
use warnings;
if (1) {
local *FH;
my $fh = \*FH;
open $fh, 'ls /usr |';
}
$_ = <FH>;
warn $_;
__END__
ls: write error
readline() on unopened filehandle FH at - line 10.
Use of uninitialized value $_ in warn at - line 12.
Warning: something's wrong at - line 12.
Or, simpler demonstration:
use strict;
use warnings;
{
open my $fh, 'ls /usr |';
}
warn "End\n";
__END__
ls: write error
End
Note how bin/ls complains before the script exits because my $fh is closed when the scope is left, before warn is called.
| [reply] [d/l] [select] |
|
|
|
|
|
|
|
Filehandles are global, irrespective of the scope in which they are referenced. To say the filehandle closes when the reference count reaches zero is incorrect.
Not quite right, as you know by now, but also not completely wrong. Filehandles are a limited resource, no matter what language you use to write your software. So it is generally a good idea to close filehandles if they are no longer needed.
Modern operating systems with a lot of memory generally allow many file handles, but still you can run out of filehandles:
>perl -Mstrict -w -E 'my @h; for my $i (1..5000) { open $h[$i],"<","/d
+ev/null" or die "$i $!"; }'
1022 Too many open files at -e line 1.
(Linux 3.10.17 x64)
C:\>perl -Mstrict -w -E "my @h; for my $i (1..5000) { open $h[$i],'<',
+'nul' or die qq[$i $!]; }"
2046 Too many open files at -e line 1.
(Windows 7 64 Bit)
Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
| [reply] [d/l] [select] |
|
|
FH contains the reference in this case. That's why you should use
open my $FH, '-|', qw{ ls usr } or die $!;
| [reply] [d/l] |
|
|
| [reply] |
Re: Scoping question - will file handle be closed?
by MidLifeXis (Monsignor) on Jul 14, 2015 at 19:45 UTC
|
Should be closed. Lexical variable falls out of scope, gets undefined, and resources assigned to it are reclaimed.
As an example:
package foo {
sub DESTROY { warn "Destroying object" }
sub new {
warn "Creating object";
return bless {}, $_[0];
}
}
warn "Before block";
{
my $obj = foo->new;
}
warn "After block";
The same basic concept lives around any lexical variable, including lexical file handles.
| [reply] [d/l] |
Re: Scoping question - will file handle be closed?
by Laurent_R (Canon) on Jul 14, 2015 at 20:35 UTC
|
Yes, it should be closed, because you are returning the lines read on $fh.
But if you changed:
local $/;
return <$fh>;
to:
# local $/; no longer useful here
return $fh;
with the idea of reading from $fh in the caller, then it will clearly remain open.
| [reply] [d/l] [select] |
|
|
I'm aware that returning $fh instead of <$fh> would keep the file handle open. I just wanted to confirm that the normal scoping rules also apply to <$fh> and there is no evil magic trickery going on behind the scenes.
What kind of evil? Hmm. Maybe <$fh> is actually evaluated lazily and does not return stuff unless someone actually reads from it keeping the $fh open. (Sorry, to much functional thinking recently...)
| [reply] |
Re: Scoping question - will file handle be closed?
by locked_user sundialsvc4 (Abbot) on Jul 14, 2015 at 21:33 UTC
|
Well, for what it’s worth, here’s the approach that I take ... in any language that I write programs in ... whenever possible.
(1) I don’t pass file-handles around. Instead, I bury them as private variables in objects that are responsible for doing, on behalf of the application, anything that has to be done with [that type of ...] file. The very fact that there is a file involved, is buried as a concern of the object. When the object is destroyed, its destructor closes the file handle explicitly. Basically, the “reference count” of that file-handle never rises above one, and the handle is never cleaned-up by virtue of going out of scope. I handle everything.
(2) Every operating system uses buffering. Even if you ask the operating system to write all the data to disk (e.g. Unix/Linux sync()), there is no positive guarantee that it will actually happen, and it is quite an expensive thing to ask an operating system to do if it actually does do what you asked. There’s only one situation where I actually asked for this, and that was when I knew that the file-buffering system (SMARTDRV.EXE, which tells you how long ago it was) was buggy, and my program was intended to fix some of the consequences of that bugginess.
(3) Programming languages ... Perl included ... use their own per-line buffering system to assemble lines of output. You can rely upon them to flush those buffers before they close the file, but if you intend to write output that does not include the line-end sequence that they’re looking for, you might have to tell them to flush.
| |