Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Implicit closing of files

by rovf (Priest)
on Jun 17, 2008 at 10:27 UTC ( #692459=perlquestion: print w/replies, xml ) Need Help??

rovf has asked for the wisdom of the Perl Monks concerning the following question:

{ ... { *local HANDLE; open(HANDLE,">outfile.txt"); print HANDLE "...."; } }

In the code above, is it guaranteed by perl that the file handle will be properly closed at the end of the inner block? I think so, and in my tests, it always worked out that way, but I got reports from a co-worker (who uses a different perl version from mine, 5.8.8, on Windows) that the buffer is occasionally not flushed at the end of the block and that he ended up with an empty file.

I was believing that when HANDLE goes out of scope (and there are no references to it alive anymore), perl would do an implicit close(HANDLE)

-- 
Ronald Fischer <ynnor@mm.st>

Replies are listed 'Best First'.
Re: Implicit closing of files
by johngg (Canon) on Jun 17, 2008 at 10:51 UTC
    I'm not sure whether there might be problems on a Windows platform, I generally use Solaris and have not had problems with implicit closing. However, I would advise the use of lexical filehandles plus the three-argument form of open and a check for success.

    { { open my $fh, q{>}, q{outfile.txt} or die qq{open: > outfile.txt: $!\n}; print $fh qq{ ... }; } }

    I hope this is of interest.

    Cheers,

    JohnGG

      3-arg open is for sure the better alternative in general, because there is no problem with "funny characters" in the filename, which could change the meaning of the open. In my concrete case however, this turns out not to be a problem.
      -- 
      Ronald Fischer <ynnor@mm.st>
Re: Implicit closing of files
by andreas1234567 (Vicar) on Jun 17, 2008 at 10:53 UTC
    The use of bareword filehandles vs .indirect filehandles is discussed in detail in Perl Best Practices. It says:
    One of the most efficient ways for Perl programmers to bring misery and suffering upon themselves and their colleagues is to write this:
    open FILE, '<', $filename or croak "Can't open '$filename': $OS_ERROR";
    Using a bareword like that as a filehandle causes Perl to store the corresponding input stream descriptor in the symbol table of the current package. Specifically, the stream descriptor is stored in the symbol table entry whose name is the same as the bareword; in this case, it's *FILE. By using a bareword, the author of the previous code is effectively using a package variable to store the filehandle.

    If that symbol has already been used as a filehandle anywhere else in the same package, executing this open statement will close that previous filehandle and replace it with the newly opened one. That's going to be a nasty surprise for any code that was already relying on reading input with <FILE>

    The advice is
    Use indirect filehandles.
    open my $FILE, '<', $filename or croak "Can't open '$filename': $OS_ERROR";
    Perl Best Practices is a controversial book, but I don't think this section is particularly debated.
    --
    No matter how great and destructive your problems may seem now, remember, you've probably only seen the tip of them. [1]
      By using a bareword, the author of the previous code is effectively using a package variable to store the filehandle.

      Hmmmm.... This does not directly relate to my question as about whether or not Perl closes the local file handle properly at the end of the block, but as to the risks of bareword file handles, I think the only risk would be if I call in my block a function, which in turn would use a non-localized filehandle of the same name.

      The file handle I as using, certainly can not close another open file handle of the same name, because it is localized.

      -- 
      Ronald Fischer <ynnor@mm.st>
        The file handle I [am] using [..] is localized.
        Sorry, I overlooked that.
        --
        No matter how great and destructive your problems may seem now, remember, you've probably only seen the tip of them. [1]
Re: Implicit closing of files
by cdarke (Prior) on Jun 17, 2008 at 11:21 UTC
    The code you supply does not compile, the asterisk is in the wrong place, should be local *HANDLE;. However, what the others are driving at is that using local on a file handle is rather dubious. With local (rather than my) the value goes out of scope, not the variable which remains a global. Nevertheless, Perl should still flush the buffer on close.
      The code you supply does not compile, the asterisk is in the wrong place, should be local *HANDLE;.
      Oops, you are right.
      With local (rather than my) the value goes out of scope, not the variable which remains a global.
      Does this mean that this variable would stay in the symbol table of the package, although there is no way that it can be "re-activated" later on?
      Nevertheless, Perl should still flush the buffer on close.
      I guess you mean: should still flush the buffer on block exit, since the whole point here is that we do not do an explicit close...
      -- 
      Ronald Fischer <ynnor@mm.st>
        I'm still puzzled why you are using local. Is your perl version so old that you do not have 'my' variables? Most would agree that 'local' is only used these days when altering system variables like $/, $|, and so on (OK, there may be other specialised uses, but these are rare).
        The replies here indicate that no one has the courage (me included) to say that 'local' has the desired effect, we just don't use it any more.
Re: Implicit closing of files
by bloonix (Monk) on Jun 17, 2008 at 11:56 UTC
    Yes, Perl does it for you, but don't you want to know if something wents wrong? I think it's a better way to close it yourself if you have a chance and check if close() wents wrong.
    close(HANDLE) or die $!;
      That's a good point indeed....
      -- 
      Ronald Fischer <ynnor@mm.st>
Re: Implicit closing of files
by dragonchild (Archbishop) on Jun 17, 2008 at 11:23 UTC
    There is a difference between Perl closing a filehandle (meaning you cannot access it in your code) and Perl flushing an output buffer (meaning all the contents have been written to disk). The buffer will definitely be flushed at the end of the script. However, if you need immediate flushing, add $| =1; right after your open() call. Alternately, take a look at IO::File and the flush() method. (Due to the documentation style of the IO distribution, you actually have to look at IO::Handle for the documentation of the flush() method. But, it is available from IO::File objects.)

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

      Are you saying the documentation is wrong? Quote close:

      Closes the file or pipe associated with the file handle, flushes the IO buffers, and closes the system file descriptor.

        That would be correct for an explicit close(). If you let the variable fall off the end of a block, now you're depending on destruction. Destruction in Perl isn't timely.

        My criteria for good software:
        1. Does it work?
        2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
      This means closing the filehandle is not the same as closing the file??? So, at the end of the block, only the file handle is closed and the file left being open (which of course then means that the buffers are not flushed yet)?
      I got my idea for using local file handles and their automatical closing from this article: Seven Useful Uses of local
      -- 
      Ronald Fischer <ynnor@mm.st>
        It's not that the file is left open per se. Perl (and every other language worth using) doesn't necessarily flush buffers immediately. close() does an explicit flush and destroys the handle. However, if you let the variable fall off the end of the scope, now you're depending on destruction to close the handle (and flush the buffer). Destruction in Perl is neither ordered nor timely.

        My criteria for good software:
        1. Does it work?
        2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: Implicit closing of files
by ikegami (Patriarch) on Jun 17, 2008 at 12:42 UTC
    Yes, unless *HANDLE or *HANDLE{IO} is still referenced by something.
    { my $fh; { local *HANDLE; open(HANDLE, '>', 'temp') or die; print HANDLE "foo\n"; $fh = *HANDLE{IO}; } print $fh "bar\n" or die; # Works. } # Now it's closed.
Re: Implicit closing of files
by syphilis (Archbishop) on Jun 17, 2008 at 11:28 UTC
    ... the buffer is occasionally not flushed at the end of the block and that he ended up with an empty file

    I couldn't get that to happen on Windows with 5.6.2, 5.8.8 or 5.10.0. Can the co-worker provide a demo ?

    Cheers,
    Rob
      Like, syphilis, me neither:
      # 692459.pl use strict; use warnings; { local *HANDLE; open(HANDLE,">outfile.txt"); print HANDLE "...."; } __END__
      # 692459.t use strict; use warnings; use Test::More tests => 4; my $f = q{outfile.txt}; require_ok(q{692459.pl}); ok(-f $f, q{file exists}); ok(-s $f, q{file's size is non-zero}); cmp_ok(unlink($f), q{==}, 1, q{Delete 1 file}); __END__
      C:\src\perl\perlmonks\692459>prove 692459.t 692459....ok All tests successful. Files=1, Tests=4, 0 wallclock secs ( 0.00 cusr + 0.00 csys = 0.00 C +PU) C:\src\perl\perlmonks\692459>perl -v This is perl, v5.8.8 built for MSWin32-x86-multi-thread
      --
      No matter how great and destructive your problems may seem now, remember, you've probably only seen the tip of them. [1]
Re: Implicit closing of files
by gokuraku (Monk) on Jun 17, 2008 at 11:34 UTC
    Back to the question at hand, from my readings of local (when I was doing some investigation of globals and such) was that outside of the scope they were invisible and unalterable, but have never seen anything that specifically mentions whether or not they are "garbage collected". I would imagine so, but being a local I can't also see why you would encounter issues with the variable in other parts of the program. For Windows scripts, the ones I use run on *nix and Windows platforms, I have never encountered problems with the buffer, but I usually place a close(HANDLE) within the script just to be clean. Though I would be curious as well if Perl does internally destruct local variables when they go out of scope, of if they hang around and are only flushed upon exit.
Re: Implicit closing of files
by Zen (Deacon) on Jun 17, 2008 at 14:56 UTC
    The problem with this post is there isn't a repro (with system spec), along with the word 'occasionally.' There can be no definitive answer without this. That being said, as others suggested, set $| and close your handle to avoid race conditions.

      Well, actually, I was looking for an answer like Perl should guarantee proper closing of the file if the file if the local handle goes out of scope, or otherwise Perl does not guarantee that this happens. Maybe I didn't made myself clear in this respect, but the problem wasn't what to do to avoid this problem (in my case, I simply put a close in the end of the block), but whether this problem (in a correct Perl installation) is supposed to appear at all; for, in case this is something which is supposed to work, but at my colleagues system it occasionally does not work, this means that we have a fundamental problem lurking somewhere on his platform which is well worth investigating. Otherwise, in case it is really undefined behaviour in Perl, but just happens to work *usually*, there is no need to research further.

      From my understanding of Perl, I could not decide this question. The link I mentioned in an earlier post seems to suggest that this is well defined behaviour in Perl, but of course this article could also be wrong, or I could have misinterpreted it. So I was hoping that someone would know what exactly happens in Perl if a local filehandle goes out of scope. Given the length of this discussion, this seems to be a dark corner in Perl.

      Actually, it maybe has implications to other areas as well. For instance, if I have a local scalar, holding a blessed reference, and this scalar goes out of scope (and there are no accesses to this reference any more); does Perl guarantee then that the DESTROY function of this object will be executed immediately, or could it be that it is called at some later time?

      -- 
      Ronald Fischer <ynnor@mm.st>
        That's fine, but you didn't provide a sample that repros on your coworker's machine, nor say what type of machine it is. Investigation cannot happen if you do not help others help you. Even if perl defined the behavior clearly, a bug may exist (even in your code).

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://692459]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (3)
As of 2022-05-17 23:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you prefer to work remotely?



    Results (68 votes). Check out past polls.

    Notices?