IzziD code logo
   
Search
Google
Topics
Home
How To
About
Subscribe in a reader
 
Other IzziDs
IzziDassorted
IzziDtravel
IzziDwetlab
IzziD
 
 
Site Map -- Disclaimer

How to move back a line when reading a perl filehandle

Article created: Jan 21, 2008
Article by: Jeremiah Faith

The angle operator <> is the standard method to read lines from a file with Perl:
my $file="myfile.txt";
open(IN, $file) or die "can't open $file: $!\n";

while (<IN>) { # place each line into $_
print; # print $_
}
The angle operator reads a single line from the file and places it into the variable you provide or into $_ if you do not provide a variable. If you use the angle operator outside of a loop, you will read a single line only.
my $file="myfile.txt";
open(IN, $file) or die "can't open $file: $!\n";
my $line = <IN>; # place a single line into $line
print $line;
Last week, I was writing a recursive function in Perl where I needed to peak at a line from the Perl filehandle. If it was the correct type of line for my recursive depth, I would process the line, otherwise I wanted to put the line back on the filehandle, so that the remaining recursive depths would have access to the line.

I dug around the Perl Camel Book and the internet, and I couldn't find a function that would allow me to unread a line. I found a few modules that would allow such a thing, but a module seemed like overkill for such a simple task. So I wrote the code myself:
my $file="myfile.txt";
open(IN, $file) or die "can't open $file: $!\n";
my $line = <IN>; # place a single line into $line
seek(IN, -length($line), 1); # place the same line back onto the filehandle
To move back a line, I use the builtin seek() function. Which takes the parameters: FILEHANDLE, OFFSET, and WHENCE. WHENCE can take a value of 0, 1, or 2. 0 = seek from the start of the file; 1 = seek from the current position; 2 = seek from the end of the file. OFFSET is the number of bytes we wish to move from the specified WHENCE position. OFFSET can be negative with a WHENCE of 1 or 2 (a negative OFFSET moves back in the file). Since each letter in an ASCII string is one byte, we simply move back from our current file position (i.e. WHENCE = 1) the number of bytes we read for the previous $line (i.e. -length($line)).

Caveats

For this function to work properly, you must call the length() function on the original string that's been read from the filehandle. If you call chomp on the line, you've likely changed the length of the string and you won't seek back far enough. This function also assumes your string contains eight bit characters.