10
$file = new SplFileObject('/path/to/file.txt');

How can I find the number of lines in a file with SplFileObject?

hakre
  • 193,403
  • 52
  • 435
  • 836
Richard Knop
  • 81,041
  • 149
  • 392
  • 552

4 Answers4

45

iterator_count and line-by-line iterating using next() is broken in my php version 5.3.7 under Ubuntu.

Also seems broken fseek([any offset], SEEK_END) method. key() returns 0.

Iterate over large files using seek($lineCount) is too slow.

Simpliest 5.3.7-verified way is

// force to seek to last line, won't raise error
$file->seek($file->getSize());
$linesTotal = $file->key();

Counting 30000 lines requires now 0.00002 secs and costs about 20 kb of memory.

Iterations method takes about 3 seconds.

  • this is wrong, seek() will look for line number while getSize() will return the filesize in bytes. – Twisted1919 Nov 02 '13 at 13:48
  • 3
    I know. It just ensures that we seeked __all__ file lines (even if all of them are empty). At most common cases, seek() will bump to EOF on line number that definitely less than bytes count, but PHP handles it silently, returning last line number. Agree, it is dirty hack, but i didn't found any "clean" way to count lines quickly. – Николай Конев Nov 25 '13 at 15:59
  • works fine. But file has 99 lines but it returns 98. do you know why? – Bala Jun 08 '17 at 12:31
  • NOTE: key returns the index of the last line so this will always be one short of the total. You need to add one to the total: `$linesTotal = $file->key() + 1;` – Simon Mar 04 '21 at 14:13
  • @Simon, can you expand on your explanation of why you need add one to the total? Do you mean because the array starts with 0, you need to add 1 to the total? – Motivated Jul 05 '23 at 10:24
  • @Motivated This was two years ago so I can't confirm any of this. But, yes, the `key()` function returns a 0-based index, meaning the total will always be +1. – Simon Jul 06 '23 at 11:57
18

I agree with Николай Конев on using seek function is much faster than going through the entire file line by line, but as Twisted1919 said using the file size to seek the last line is confusing so my suggestion is use PHP_INT_MAX instead of the file size:

// force to seek to last line, won't raise error
$file->seek(PHP_INT_MAX);
$linesTotal = $file->key();
Community
  • 1
  • 1
emont01
  • 3,010
  • 1
  • 22
  • 18
6

The SplFileObject offers an itertor, one iteration per line:

$numberOfLines = iterator_count($file);

The function iterator_count is your friend here, doing the traversal for you and returning the number of iterations.

You can make use of the file object's SKIP_EMPTY flag to not count empty lines in that file.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • 1
    Great answer but on larger file (10mb and 135,000+ lines in this case) it is entirely too slow and an attempt to count using this method actually results in a time out. – Typo Sep 20 '13 at 03:28
4

Why not simply use file handlers and do like in this question? Its simple, fast and very efficient.

If you absolutely must use spl, you can do it like this

$file = new SplFileObject("/path/to/file.txt");
$i = 0;
while (!$file->eof()) {
    $i++;
    $file->next();
}
print "file has " . $i . " lines"; 
Community
  • 1
  • 1
Jan Dragsbaek
  • 8,078
  • 2
  • 26
  • 46
  • I used fopen/fgets traditional way of reading files as you recommended, thanks. Sometimes I am just trying to do everything with classes when it's not needed. – Richard Knop Dec 01 '11 at 15:56
  • If you want to do your filehandling in an object oriented way, thats exactly why SPL exists. – Jan Dragsbaek Dec 01 '11 at 15:57