Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw

Able to open file, unable to read

by feiiiiiiiiiii (Acolyte)
on May 13, 2016 at 19:51 UTC ( #1162984=perlquestion: print w/replies, xml ) Need Help??

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

Hi guys,

I recently came across a weird error. It happened a few times. Seems very random, but usually tend to happen around a specific time. Below is the code:

my $file_name = 'abc.txt'; # abc.txt is just one line simple txt file like "Hello world!". It's c +reated by another program. The second the other program creates it, t +he code below tries to read it. # I know the following code is not the right thing to do. I would do i +t open (my $FILE, '<', $file_name) for reading. But it's legacy code +and how the error is produced. So I just show it the way it is now. open(FILE, $file_name) or die "Can't open file $file_name $!\n"); my $line = <FILE>; print $line;

The random error is, it's able to open the file (the die action never happens), but unable to read any data ($line is uninitialized)

If I rerun it after a couple minutes, it runs fine and $line does get the data

My best guess is that the bug is due to legacy "open(FILE, $file_name)" code. Because it did not specify "<" read mode, after it opens the file successfully, another program somehow gets able to write it. Then this program was not able to read it. Is that a fair guess? Anybody has better idea how to fix it? Thanks!

Replies are listed 'Best First'.
Re: Able to open file, unable to read
by Apero (Scribe) on May 13, 2016 at 20:36 UTC
    The random error is, it's able to open the file (the die action never happens), but unable to read any data ($line is uninitialized)

    Since your code isn't hitting the die() after the open() call, the program found the file and had permission to open it. Chances are good you just attempted to read an empty file.

    As perlop will explain under the I/O Operators heading, the angled-bracket read returns undef in scalar context when you're at EOF (end-of-file.) If you care about this condition, you should test the definedness of $line before using it, and possibly report EOF as an error condition to the invoker of the script rather than try to use it.

    I can reproduce the condition you're seeing by running the code shown at the bottom of this post (which I call with the following test. Note that I'm on a Unix-alike, so you may need to populate an empty file a different way as defined by your OS. Also note that I replace an undefined result with a notice that the line was in fact undefined, using the // operator. This should illustrate the problem I suspect you're having.

    Test case:

    cp /dev/null file.txt perl ./ echo "hello world" > file.txt perl ./

    use strict; use warnings; my $file_src = 'file.txt'; open(my $fh, '<', $file_src) or die "open() failed: $!"; my $line = <$fh>; close($fh) or die "close() failed: $!"; printf( "Got a line: %s", $line // '<line-was-undef>' );
Re: Able to open file, unable to read
by stevieb (Canon) on May 13, 2016 at 20:01 UTC
    Is the other app wiping it and re-populating it at the same time your script is reading it? You may want to force the other app create a copy after it's finished, then work on the copy in your perl script. I doubt it's due to the legacy open, but I've been wrong before ;)
Re: Able to open file, unable to read
by Marshall (Canon) on May 14, 2016 at 09:09 UTC
    I also agree that the old style file open is not an issue - should work fine. Apero's post shows what can happen if the file is "empty", you would get EOF.

    If the writer of this file has it open, it is possible for there not to be anything in it yet, but yet possible for you to have it open for read. One of those reasons could be output buffering. Typically the writer will have to "write" at least 1K before the data gets flushed to the disk.

    Perl has some built file test operators, my $size = -s $filename should give you the current file size that you are able to read.

    So without fixing the writer to turn off buffering, by say adding $|=1, you could loop for a while, checking $size every second or so (sleep(1) or whatever) for a few minutes. Don't try to read from the open filehandle until $size>0. Usually once you hit "EOF", you can't read past that, but you can delay reading until something is actually available for you to read. That way you won't hit EOF.

    Basically this idea just automates the "wait a few minutes" and try again part. Also adding this $size check to the code would I think be of diagnostic value, if you are getting undef read value (EOF) and $size>0, then there is some other problem.

    PS: what O/S are you using?

    Update: Perl File Test Operators

Re: Able to open file, unable to read
by ExReg (Priest) on May 13, 2016 at 20:15 UTC

    I tried it and had no such problem (after removing extraneous ')' at end of open statement). perldoc -f open says that if '<' is omitted, it opens for input. Something else must be going on.

Re: Able to open file, unable to read
by Anonymous Monk on May 13, 2016 at 20:16 UTC

    Has the other program closed the file before your program starts ?

Log In?

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

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2021-12-09 08:13 GMT
Find Nodes?
    Voting Booth?
    R or B?

    Results (36 votes). Check out past polls.