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

I have a file I've opened,

open TF, "< $tfile" ; foreach $line (<TF>) {
somewhere in the body, I realize that what I need is on the next line of the file.


Is there a way within the foreach loop to get the next line? And is there a way to advance the file handle so it doesn't re-read the next line in the foreach loop?

Replies are listed 'Best First'.
Re: advancing in file read
by almut (Canon) on May 15, 2010 at 20:46 UTC

    Use a while loop instead, and then just do another $line = <TF>; within the loop body. This will both read the next line and advance the file pointer.

    while ($line = <TF>) { ... $line = <TF>; }

    The problem with the for loop is that all the lines already have been read (because of <TF> being in list context) before the loop starts iterating.

      Thanks!
Re: advancing in file read
by biohisham (Priest) on May 16, 2010 at 04:28 UTC
    is there a way to advance the file handle so it doesn't re-read the next line
    If you know the line lengths in the file are uniform then using seek allows you to randomly access file contents as opposed to sequential access hence a position in a file can be reached directly without having to go through the file from the beginning, however, that needs you to know the file content details and to account for the effect of buffering (check the above link). Seek has the syntax 'seek FILEHANDLE, POSITION, WHENCE;' WHENCE specifies the interpretation of POSITION, it can be either 0,1, or 2.
    • 0-> sets the new position to POSITION.
    • 1-> sets the new position to the current position plus POSITION.
    • 2-> sets the new position to the end of file plus POSITION.

    Also reading a file via IO modules provides support for seek through the IO::Seekable interface

    use IO::File; use IO::Seekable; $|++; # turn off buffering... my $handle = new IO::File; $handle->open("<FileHello.txt")or die("error $!\n"); $handle->seek(12,0); while(<$handle>){ print; } $handle->close;


    Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind.
Re: advancing in file read
by choroba (Cardinal) on May 16, 2010 at 11:22 UTC
    Or, you can switch between two states of your loop, one looking for the first line, and the second looking for the next line:
    my $state = 0; foreach my $line (<TF>){ if($state){ # do whatever you need with the "next" line $state = 0; } else { # do what you normally do if($next_line_needed){ $state = 1; } } }
Re: advancing in file read
by Marshall (Canon) on May 16, 2010 at 19:34 UTC
    Is there a way within the foreach loop to get the next line?

    Within the foreach() loop use a "next if ...bla..; statement. That will re-start the loop and get the next line. This works in while() loops also.

    To suppress another read, while($no_read && <DATA>){}. This is better than some languages or constructs that use an "un-read" function and is very useful in some parsing situations. Fiddle with the $no_read flag to get the result you require.

    I guess while we are on this subject, Perl has a redo function. I use that with extreme caution, but that doesn't mean never use it.

Re: advancing in file read
by apl (Monsignor) on May 16, 2010 at 13:21 UTC
    Depending on the size of the file (and your needs) you could read the entire file into an array, and then loop through the array...
      How is that different than what he is doing now (reading the entire file into a list, then looping through the list)? Your solution is incomplete.
        You are correct; thanks.
        1. Read the file into an array without processing the content.
        2. Set an index to 0
        3. Process the contents of the current index of the array. If said contents require information on the next line, refer to the (index + 1) element of the array.
        4. Increment the index by 1 or 2, as appropriate.