in reply to Scoping question - will file handle be closed?

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
  • Comment on Re: Scoping question - will file handle be closed?

Replies are listed 'Best First'.
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?


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
    I'm with torvalds on this Agile (and TDD) debunked I told'em LLVM was the way to go. But did they listen!
      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.)
      Warn the user that there's something wrong. The most likely cause is Perl failed to write the data to disk.
        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:

        1. 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.

        2. 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.

        3. 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?


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
        I'm with torvalds on this Agile (and TDD) debunked I told'em LLVM was the way to go. But did they listen!
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!

    One world, one people

      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.

      oh well, I can't retract what I know to be true!

      No, because that would involve learning something?

      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.

      - tye        

        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.

        One world, one people

      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". ;-)
      FH contains the reference in this case. That's why you should use
      open my $FH, '-|', qw{ ls usr } or die $!;
      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      After the closing braces, there is nothing left in scope. In spite of that the filehandle FH remains open

      ... which means that FH is indeed still in scope and that the reference count is therefore non-zero.