views:

84

answers:

4

Hello,

Is there a way to read a file in PHP5 from line X to line Y into a string, without reading the entire file.

I would like to return huge files (10,000+ lines) using ajax requests. Each request will provide the client with additional lines. And due to the fact that the file can reach large sizes, I would like to avoid reading it whole over and over again.

Thank you.

+3  A: 

Here is the possible solution :)

<?php
$f = fopen('sample.txt', 'r');
$lineNo = 0;
$startLine = 3;
$endLine = 6;
while ($line = fgets($f)) {
    $lineNo++;
    if ($lineNo >= $startLine) {
        echo $line;
    }
    if ($lineNo == $endLine) {
        break;
    }
}
fclose($f);
?>
Sarfraz
In your solution the whole file is read.
x2
But it reads all lines before X. The question is asking if this part can be skipped, isn't it?
MartyIX
See the `$startLine` and `$endLine` variables, it will read only those lines.
Sarfraz
MartyIX
It's a nice solution, but still time consuming.The deeper you go into a file the longer it will take... And I intend to work with files that have 10,000+ lines.
thedp
@thedp: let's see if there is a better solution :)
Sarfraz
@Sarfraz: What do you think of my so called "plan B" solution? http://stackoverflow.com/questions/2808583/read-a-file-from-line-x-to-line-y/2808707#2808707
thedp
@Sarfraz: BTW, nice code reuse - http://stackoverflow.com/questions/514673/how-do-i-open-a-file-from-line-x-to-line-y-in-php/514717#514717
thedp
@thedp: in the my asnwer, the first link points to that source, i posted it here for some users based on their comments so that things were clarified.
Sarfraz
@Sarfraz: lol, relax man. I said reuse and copy :)
thedp
+3  A: 

Well, you can't use function fseek to seek the appropriate position because it works with given number of bytes.

I think that it's not possible without some sort of cache or going through lines one after the other.

MartyIX
What about a line cache? Store somewhere the byte positions of each line, then use fseek() to get to them.
christian studer
It would be a nice solution.
MartyIX
@christian studer: You're talking about Indexing a file? This could be an interesting solution if the file was static and wouldn't change most of the time. Unfortunately, the files I'm going to read are source-code files still in development, so indexing is out of the question.
thedp
Yes, indexing it and cache the index. (The timestamp on the file might give an indication if the cached index is still valid).PHP is surprisingly fast for these tasks, and if you have several requests for the same file before it changes again, might be fast enough to pull this off.
christian studer
A: 

I was afraid of that... I guess it's plan B then :S

For each AJAX request I'm going to:

  1. Read into a string the number of lines I'm going to return to the client.
  2. Copy the rest of the file into a temp file.
  3. Return string to the client.

It's lame, and it will probably be pretty slow with 10,000+ lines files, but I guess it's better than reading the same over and over again, at least the temp file is getting shorter with every request... No?

thedp
+4  A: 

Yes, you can do that easily with SplFileObject::seek

$file = new SplFileObject('filename.txt');
$file->seek(1000);
for($i = 0; !$file->eof() && $i < 1000; $i++) {
    echo $file->current(); 
    $file->next();
}

This is a method from the SeekableIterator interface and not to be confused with fseek.

And because SplFileObject is iterable you can do it even easier with a LimitIterator:

$file = new SplFileObject('longFile.txt');
$fileIterator = new LimitIterator($file, 1000, 2000);
foreach($fileIterator as $line) {
    echo $line, PHP_EOL;
}

Again, this is zero-based, so it's line 1001 to 2001.

Gordon
+1 SPL is very nice and could use more advertisement (and documentation)
kemp
Wow, I did not know that one, thank you very much!
christian studer
Just remember that the SPL implementation is implemented in the same manner as the first suggested solution. It will start reading the file from the first byte, one line at a time, and leave the file pointer at the desired line.There is no way to get around that issue.
fiskfisk