0

Is there an efficient way to replace the last line from a file?

I need this for log files, to have this kind of line:

21:00:00 - Info - Count: 3

Be replaced with this:

21:00:35 - Info - Count: 4

And so on.. So it looks cool in a tail -f

The problem is that log files can get really big, and I don't want them being loaded into the memory everytime I want to replace the last line.

Anyway, if loading the whole file was the only way, how would you go about it, having in mind that there are other scripts appending data to the same file, simultaneously? I guess I have to lock it or something. I never used that because I just use file_put_contents with the FILE_APPEND option.

HappyDeveloper
  • 12,480
  • 22
  • 82
  • 117
  • seek to end, backtrack to previous CR/LF. But why bother just append the later count.... – Mitch Wheat Mar 23 '11 at 16:04
  • possible duplicate of [remove All lines except first 20 using php.](http://stackoverflow.com/questions/4410077/remove-all-lines-except-first-20-using-php/4410342#4410342) – Gordon Mar 23 '11 at 16:06
  • Agree with @Mitch. Specifically, I'd raise a concern about deliberately altering the contents of a logfile. Logfiles, IMHO, should be treated as append-only by the application. – Bob Kaufman Mar 23 '11 at 16:06
  • *(related)* [Save memory when reading a file in php](http://stackoverflow.com/questions/2603807/how-to-save-memory-when-reading-a-file-in-php/2603923#2603923) and [Reading a specific line from a text file](http://stackoverflow.com/questions/4718305/reading-a-specific-line-from-a-text-file/4718338#4718338) and [Getting one line in a huge file with php](http://stackoverflow.com/questions/2794056/getting-one-line-in-a-huge-file-with-php) – Gordon Mar 23 '11 at 16:08

1 Answers1

1

If you want an efficient way, then read in a block of content from the end, then truncate on the last found \n. That's not pretty, but works:

$fn = "LICENSE";
$size = filesize($fn);
$block = 4096;
$trunc = max($size - $block, 0);

$f = fopen($fn, "c+");
if (flock($f, LOCK_EX)) {
   fseek($f, $trunc);
   $bin = rtrim(fread($f, $block), "\n");
   if ($r = strrpos($bin, "\n")) {
      ftruncate($f, $trunc + $r + 1);
   }
}
fclose($f);   // clears LOCK_EX
mario
  • 144,265
  • 20
  • 237
  • 291
  • This is perfect. The only problem is that the lock doesn't seem to be cleared by fclose(). I'm on windows, and netbeans won't let me even read the file. I just added flock($f,LOCK_UN) and it worked. Thanks a lot =) – HappyDeveloper Mar 23 '11 at 17:35