After you get the length of the line
my $row_len = length <$fh>; # with newline, or (read then) chomp first
position the handle where you need it using seek
use Fcntl qw(:seek);
seek $fh, $row_len/2, SEEK_SET;
where Fcntl provides constants SEEK_SET
, SEEK_CUR
, and SEEK_END
so that the position in the second argument is taken from either the beginning, or the current position, or the end of file (when a negative position is normally used). Instead of these one can use 0
, 1
, 2
.
Then read $bytes
into $data
using read
my $bytes = 100;
my $data;
my $rb = read $fh, $data, $bytes;
where $rb
is how many bytes were actually read out of $bytes
requested.
For some filehandles (sockets for one) read
may not get as much as requested at once so you'd need to keep reading. For example, using OFFSET
(see docs) at which to write to the string
use bytes qw();
my ($data, $requested, $total_read) = ('', 100, 0);
while ($total_read < $requested) {
my $bytes_data = bytes::length $data;
$total_read += read $fh, $data, $requested - $bytes_data, $bytes_data;
}
where read
now writes to $data
at position $bytes_data
. Without that offset each read overwrites $data
, what can be appended to a string with all data (or otherwise accumulated).
While bytes::length
is fine the bytes pragma is in general "strongly discouraged".
Thanks to ikegami for comments.
Note that read
doesn't treat "newlines" in any special way and a read may well pick up from the next line(s) of the file, while those newline-bytes do count and thus affect your position in a file.
It is not specified what you want to do next but you can keep (repositioning and) reading.
See this post for a crystal clear explanation of moving in a file with seek
and read
.