package File::CountLines; use strict; use warnings; our $VERSION = '0.0.3'; our @EXPORT_OK = qw(count_lines); use Exporter 5.057; Exporter->import('import'); use Carp qw(croak); use charnames qw(:full); our %StyleMap = ( 'cr' => "\N{CARRIAGE RETURN}", 'lf' => "\N{LINE FEED}", 'crlf' => "\N{CARRIAGE RETURN}\N{LINE FEED}", 'native' => "\n", ); our $BlockSize = 4096; sub count_lines { my $filename = shift; croak 'expected filename in call to count_lines()' unless defined $filename; my %options = @_; my $sep = $options{separator}; unless (defined $sep) { my $style = exists $options{style} ? $options{style} : 'native'; $sep = $StyleMap{$style}; die "Don't know how to map style '$style'" unless defined $sep; } if (length($sep) > 1) { return _cl_sysread_multiple_chars( $filename, $sep, $options{blocksize} || $BlockSize, ); } else { return _cl_sysread_one_char( $filename, $sep, $options{blocksize} || $BlockSize, ); } } sub _cl_sysread_one_char { my ($filename, $sep, $blocksize) = @_; local $Carp::CarpLevel = 1; open my $handle, '<:raw', $filename or croak "Can't open file `$filename' for reading: $!"; binmode $handle; my $lines = 0; $sep =~ s/([\\{}])/\\$1/g; # need eval here because tr/// doesn't interpolate my $sysread_status; eval qq[ while (\$sysread_status = sysread \$handle, my \$buffer, $blocksize) { \$lines += (\$buffer =~ tr{$sep}{}); } ]; die "Can't sysread() from file `$filename': $!" unless defined ($sysread_status); close $handle or croak "Can't close file `$filename': $!"; return $lines; } sub _cl_sysread_multiple_chars { my ($filename, $sep, $blocksize) = @_; local $Carp::CarpLevel = 1; open my $handle, '<:raw', $filename or croak "Can't open file `$filename' for reading: $!"; binmode $handle; my $len = length($sep); my $lines = 0; my $buffer = ''; my $sysread_status; while ($sysread_status = sysread $handle, $buffer, $blocksize, length($buffer)) { my $offset = -$len; while (-1 != ($offset = index $buffer, $sep, $offset + $len)) { $lines++; } # we assume $len >= 2; otherwise use _cl_sysread_one_char() $buffer = substr $buffer, 1 - $len; } die "Can't sysread() from file `$filename': $!" unless defined ($sysread_status); close $handle or croak "Can't close file `$filename': $!"; return $lines; } 1; __END__ =head1 NAME File::CountLines - efficiently count the number of line breaks in a file. =head1 SYNOPSIS use File::CountLines qw(count_lines); my $no_of_lines = count_lines('/etc/passwd'); # other uses my $carriage_returns = count_lines( 'path/to/file.txt', style => 'cr', ); # possible styles are 'native' (the default), 'cr', 'lf' =head1 DESCRIPTION L answers the question on how to count the number of lines in a file. This module is a convenient wrapper around that method, with additional options. More specifically, it counts the number of I rather than lines. On Unix systems nearlly all text files end with a newline (by convention), so usually the number of lines and number of line breaks is equal. Since different operating systems have different ideas of what a newline is, you can specifiy a C