Reading large files from end

Viewed 18668

Can I read a file in PHP from my end, for example if I want to read last 10-20 lines?

And, as I read, if the size of the file is more than 10mbs I start getting errors.

How can I prevent this error?

For reading a normal file, we use the code :

if ($handle) {
    while (($buffer = fgets($handle, 4096)) !== false) {
    $i1++;
    $content[$i1]=$buffer;
    }
    if (!feof($handle)) {
        echo "Error: unexpected fgets() fail\n";
    }
    fclose($handle);
}

My file might go over 10mbs, but I just need to read the last few lines. How do I do it?

Thanks

11 Answers

If you know about how long the lines are, you can avoid a lot of the black magic and just grab a chunk of the end of the file.

I needed the last 15 lines from a very large log file, and altogether they were about 3000 characters. So I just grab the last 8000 bytes to be safe, then read the file as normal and take what I need from the end.

    $fh = fopen($file, "r");
    fseek($fh, -8192, SEEK_END);
    $lines = array();
    while($lines[] = fgets($fh)) {}

This is possibly even more efficient than the highest rated answer, which reads the file character by character, compares each character, and splits based on newline characters.

A more complete example of the "tail" suggestion above is provided here. This seems to be a simple and efficient method -- thank-you. Very large files should not be an issue and a temporary file is not required.

$out = array();
$ret = null;

// capture the last 30 files of the log file into a buffer
exec('tail -30 ' . $weatherLog, $buf, $ret);

if ( $ret == 0 ) {

  // process the captured lines one at a time
  foreach ($buf as $line) {
    $n = sscanf($line, "%s temperature %f", $dt, $t);
    if ( $n > 0 ) $temperature = $t;
    $n = sscanf($line, "%s humidity %f", $dt, $h);
    if ( $n > 0 ) $humidity = $h;
  }
  printf("<tr><th>Temperature</th><td>%0.1f</td></tr>\n", 
          $temperature);
  printf("<tr><th>Humidity</th><td>%0.1f</td></tr>\n", $humidity);
}
else { # something bad happened }

In the above example, the code reads 30 lines of text output and displays the last temperature and humidity readings in the file (that's why the printf's are outside of the loop, in case you were wondering). The file is filled by an ESP32 which adds to the file every few minutes even when the sensor reports only nan. So thirty lines gets plenty of readings so it should never fail. Each reading includes the date and time so in the final version the output will include the time the reading was taken.

Related