my $block_size = 1000; my $max_line_size = 10000; my $buf = ''; my $offset = 0; my $read; my $line; my $pos; READ_LINE: for (;;) { EXTRACT_LINE: for (;;) { $pos = index($buf, $/); if ($pos >= 0) { $line = substr($buf, 0, $pos+1, ''); $offset = 0; last EXTRACT_LINE; } FILL_BUF: for (;;) { my $to_read; if ($offset + $block_size > $max_line_size) { $to_read = $max_line_size - $offset; } else { $to_read = $block_size; } if (not $to_read) { SKIP_LONG_LINE: for (;;) { $read = read($fh, $buf='', $block_size, $offset=0); die("Unable to read: $!") if not defined $read; if (not $read) { $line = undef; $offset = 0; last READ_LINE; } $pos = index($buf, $/); if ($pos >= 0) { substr($buf, 0, $pos+1, ''); $offset = $read - ($pos+1); last SKIP_LONG_LINE; } } next EXTRACT_LINE; } $read = read($fh, $buf, $to_read, $offset); die("Unable to read: $!") if not defined $read; if (not $read) { if (not $offset) { $line = undef; $offset = 0; last READ_LINE; } else { $line = $buf; $buf = ''; $offset = 0; last EXTRACT_LINE; } } $pos = index($buf, $/, $offset); if ($pos >= 0) { $line = substr($buf, 0, $pos+1, ''); $offset = 0; last EXTRACT_LINE; } $offset += $read; } } ...do something with $line... }