tags:

views:

115

answers:

4

How do I read a file backwards line by line using fseek?

code can be helpful. must be cross platform and pure php.

many thanks in advance

regards

Jera

+5  A: 

You cannot fseek line by line, because you do not know how long the lines are until you read them.

You should either read the whole file into a list of lines, or if the file is too big for that and you only need the last lines, read fixed-sized chunks from the end of the file and implement a bit more complicated logic which detects lines from such data.

zvonimir
+8  A: 

If you are going to read the entire file in anyways, just use file() to read the file in as an array (each line is each element in the array) and then use array_reverse() to flip the array backwards and loop through that. Or just do a reverse for loop where you start at the end and decrement on each loop.

$file = file("test.txt");
$file = array_reverse($file);
foreach($file as $f){
    echo $f."<br />";
}
Jonathan Kuhn
+2  A: 

To completely reverse a file:

$fl = fopen("\some_file.txt", "r");
for($x_pos = 0, $output = ''; fseek($fl, $x_pos, SEEK_END) !== -1; $x_pos--) {
    $output .= fgetc($fl);
    }
fclose($fl);
print_r($output);

Of course, you wanted line-by-line reversal...


$fl = fopen("\some_file.txt", "r");
for($x_pos = 0, $ln = 0, $output = array(); fseek($fl, $x_pos, SEEK_END) !== -1; $x_pos--) {
    $char = fgetc($fl);
    if ($char === "\n") {
        // analyse completed line $output[$ln] if need be
        $ln++;
        continue;
        }
    $output[$ln] = $char . ((array_key_exists($ln, $output)) ? $output[$ln] : '');
    }
fclose($fl);
print_r($output);

Really though, Jonathan Kuhn has the best answer IMHO above. The only cases you'd not use his answer that I know of is if file or like functions are disabled via php.ini, yet the admin forgot about fseek, or when opening a huge file just get the last few lines of contents would magically save memory this way.

Note: Error handling not included. And, PHP_EOL didn't cooperate, so I used "\n" to denote end of line instead. So, above may not work in all cases.

bob-the-destroyer
A: 

Reading the entire file into an array and reversing is fine unless the file is enormous.

You could perform a buffered read of your file from back to front with something like this:

  • establish a buffer_size B - this should be longer than the longest anticipated line otherwise you'll need some logic for growing the buffer size when lines are too long
  • set offset = file length - buffer_size
  • while the offset>=0
    • read buffer_size bytes from offset
    • read a line - it will be incomplete as we'll have jumped into the middle of a line, so we want to ensure the next buffer we read ends with it. Set offset = offset - buffer_size + line length
    • discard that line, read all following lines into an array and reverse them
    • process this array to do whatever you wanted to do
Paul Dixon