Re^2: Scoping question - will file handle be closed?
by BrowserUk (Patriarch) on Jul 14, 2015 at 19:37 UTC
|
However, this automatic close does not check for errors, so it is better to explicitly close filehandles, especially those used for writing
Besides knowing it, I always wondered what you're meant to do if you detect an error when closing a file?
| [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] |
|
|
Warn the user that there's something wrong.
Okay. But "Something's wrong!" isn't very useful to the user.
According to POSIX, close can fail with one of 3 errors:
- EBADF: fd isn't a valid open file descriptor.
Hopefully, if this can occur in the application, it'll be detected/sorted before the user gets his hands in it.
- EINTR: The close() call was interrupted by a signal; see signal(7).
Ditto. If this is a possibility, a signal handler will have been installed to handle it.
- EIO: An I/O error occurred.
And we're back to "Something's wrong!".
And then, the man page says:"A successful close does not guarantee that the data has been successfully saved to disk, as the kernel defers writes.", so even a successful close doesn't guarantee good data.
So we've told the user, "Something's wrong!, but not what. And even if we haven't told him, something could still be wrong. So where does that leave him?
He could decide to re-run the process to recreate the file; but what if it (whatever "it" is) happens again?
And, it could be he does so unnecessarily, because it was only the close that failed and not the preceding writes.
And what can he do about the failures that happen after we've closed the file; due to caching?
In the end, the only arbiter of whether the file is good is whether the next use of that file is successful.
So, the only sure way to detect the types of problems that might be indicated by close failing, is to ensure that the next process in the chain; even if that is a human being reading the file, can adequately detect that the file is incomplete or otherwise corrupted. Perhaps a sentinel record ("The end") or an known file size.
And whatever mechanism is put in place for the next process to detect the error; negates any purpose in detecting and warning that "Something's wrong!";
Did I miss a possibility?
| [reply] |
|
|
|
|
|
|
|
|
|
|
Re^2: Scoping question - will file handle be closed?
by anonymized user 468275 (Curate) on Jul 17, 2015 at 10:05 UTC
|
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] |
|
|
Yes I know what 'local' does, but this topic has nothing to do with the use of local. Please refrain from confusing people at a lower level than yourself, who need to know, for example, how global variables work!
You could have said, for example, 'Although globals including filehandles do not go out of scope, this behaviour can be avoided using the local keyword' (and then put your example).
Update: in your second example your variable is specifically of lexical scope, but there is an underlying global that gets assigned to $fh which doesn't go out of scope. OK looks like there's a trick going on here. $fh becomes \*{'::$fh'} which is a global that depends on a local. So although the filehandle isn't closed, it does become lexically inaccessible.
| [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.
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] |