Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

Open file issues

by hotshot (Prior)
on Aug 18, 2004 at 09:39 UTC ( #383906=perlquestion: print w/replies, xml ) Need Help??
hotshot has asked for the wisdom of the Perl Monks concerning the following question:

Hi all!

I have the following function for openning a file:
sub openFile { my ($file, $accessMode) = @_; my $err; if (! defined($accessMode)) { # by default, open the file for re +ading $accessMode = $MODE_READ; } if (exists($ACCESS_MODES{$accessMode})) { if (! open(FILE, "$ACCESS_MODES{$accessMode}$file")) { $err = $!; if (defined($returnOnError)) { return $FALSE; } &throwGenError("Can't open $file: $err"); # throw except +ion } } else { &throwGenError("In openFile: Wrong access mode $accessMode"); } return FILE; }
The problem is when I call it in a function, and before closing the file handler I call another function the also opens a file (another file), for example:
sub func1 { my (@fileContent,@temp, @comment); my $contentFh = &openFile($file1); while (my $line = <$contentFh >) { ... push(@fileContent,&func2($line)); ... } } close($contentFh); return \@fileContent; } sub func2 { my ($user) = @_; my @groupsFile; my $groupsFh = &openFile($file2); @groupsFile = <$groupsFh>; close($groupsFh); ... return @groupsFile; }
When calling func1 I get the following errors to screen:
readline() on closed filehandle FILE at /var/www/cgi-bin/lib/ + line 25.
It's the leine of the while(). It doesn't happen when I don't call func2 from within func1, I guess the close() call in func2 somehow effects func1.
Anywhy can explain the problem and suggest a solution?

Thanks a lot

Replies are listed 'Best First'.
Re: Open file issues
by davorg (Chancellor) on Aug 18, 2004 at 09:55 UTC

    If you were running with "use warnings" then Perl would have told you what the problem is. Filehandles aren't first-class variables in Perl so you can't just return a filehandle from a function and assign it to a variable like that. You're actually using the same filehandle (FILE) for both files - which is why you can't use it after you've closed the first filehandle.

    You can get round this by using lexical filehandles.

    sub openFile { my ($file, $accessMode) = @_; my $err; $accessMode = $MODE_READ unless defined $accessMode; if (exists($ACCESS_MODES{$accessMode})) { if (open(my $fh, "$ACCESS_MODES{$accessMode}$file")) { return $fh; } else { $err = $!; if (defined($returnOnError)) { return; } &throwGenError("Can't open $file: $err"); # throw exception } } else { &throwGenError("In openFile: Wrong access mode &accessMode"); } return; }

    Some of your logic is a bit scary, so I haven't changed too much. You might need to check it carefully.


    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

      Some of your logic is a bit scary, so I haven't changed too much. You might need to check it carefully. Can you explain what you ment?

      And thanks for your pre answer

        Oh, I just mean that there are a few globals which make me a bit uncomfortable and your error handling is (to my eyes) a bit bizarre. The more "Perlish" approach would be to return a false value for smaller errors and to just die on fatal stuff.


        "The first rule of Perl club is you do not talk about Perl club."
        -- Chip Salzenberg

Re: Open file issues
by eserte (Deacon) on Aug 18, 2004 at 09:55 UTC
    All the files in your script share one filehandle, FILE. You have two options to solve this problem: use Symbol::gensym() to create unique filehandles, or use lexicals instead of bareword filehandles. The latter option requires you to have a new perl (5.6 or 5.8, I can't remember). The code would look like this:
    my $fh; open($fh, "...") or die ...; return $fh;

      You could also use IO::File which should work in even older perls.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://383906]
Approved by eserte
[Corion]: Hurr. Yesterday I played around with ffmpeg as a new toy and found its "scene" filter great - it detects scene changes. Now I could write a module that splits a given video on its cuts into different scenes. Except I have no use case for that :)
[Corion]: (and also, writing yet another FFmpeg module just to wrap system() and grep through its output isn't all that great ...)
[erix]: cut out advertisements from movies? :)
[erix]: robably not possible (or it would have been done already)
[Corion]: erix: Oooh - yeah, that would be a good application of this, true (except that I don't consume movies-with- separate- advertisements that much nowadays :) )
[erix]: yes, it's old annoyance :)
[Corion]: erix: I think it's basically quite possible through a variety of means - change in audio level (advertisements are usually louder), common "advertisement starting" blocks, fade in/out of TV logo

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (11)
As of 2018-05-24 11:14 GMT
Find Nodes?
    Voting Booth?