Remove The Last Line From A File In PHP

8th May 2010 - 5 minutes read time

Removing the last line from a file is an easy process and can be done in just a few lines of code.

  1. // Read the file into an array
  2. $lines = file('file.txt');
  3.  
  4. // Pop the last item from the array
  5. array_pop($lines);
  6.  
  7. // Join the array back into a string
  8. $file = join('', $lines);
  9.  
  10. // Write the string back into the file
  11. $file_handle = fopen('file.txt', 'w');
  12. fputs($file_handle, $file);
  13. fclose($file_handle);

One limitation of the approach in this script is that if the file is quite large then passing the entire file into an array will use quite a bit of memory, potentially causing the server to simply fall over. Rather than do this the best approach is to go from the end of the file backwards until we spot the first line break. The following script will bite off 50 characters at a time until a line break is found (not the one at the end of the file). At which point the loop exits and the file up until the found line break is written back into the file.

  1. // Filename
  2. $filename = 'file.txt';
  3.  
  4. // Open file
  5. $file_handle = fopen($filename, 'r');
  6.  
  7. // Set up loop variables
  8. $linebreak = false;
  9. $file_start = false;
  10.  
  11. // Number of bytes to look at
  12. $bite = 50;
  13.  
  14. // File size
  15. $filesize = filesize($filename);
  16.  
  17. // Put pointer to the end of the file.
  18. fseek($file_handle, 0, SEEK_END);
  19.  
  20. while ($linebreak === false && $file_start === false) {
  21. // Get the current file position.
  22. $pos = ftell($file_handle);
  23.  
  24. if ($pos < $bite) {
  25. // If the position is less than a bite then go to the start of the file
  26. rewind($file_handle);
  27. } else {
  28. // Move back $bite characters into the file
  29. fseek($file_handle, -$bite, SEEK_CUR);
  30. }
  31.  
  32. // Read $bite characters of the file into a string.
  33. $string = fread($file_handle, $bite) or die ("Can't read from file " . $filename . ".");
  34.  
  35. /* If we happen to have read to the end of the file then we need to ignore
  36.   * the last line as this will be a new line character.
  37.   */
  38. if ($pos + $bite >= $filesize) {
  39. $string = substr_replace($string, '', -1);
  40. }
  41.  
  42. // Since we fred() forward into the file we need to back up $bite characters.
  43. if ($pos < $bite) {
  44. // If the position is less than a bite then go to the start of the file
  45. rewind($file_handle);
  46. } else {
  47. // Move back $bite characters into the file
  48. fseek($file_handle, -$bite, SEEK_CUR);
  49. }
  50.  
  51. // Is there a line break in the string we read?
  52. if (is_integer($lb = strrpos($string, "\n"))) {
  53. // Set $linebreak to true so that we break out of the loop
  54. $linebreak = true;
  55. // The last line in the file is right after the linebreak
  56. $line_end = ftell($file_handle) + $lb + 1;
  57. }
  58.  
  59. if (ftell($file_handle) == 0) {
  60. // Break out of the loop if we are at the beginning of the file.
  61. $file_start = true;
  62. }
  63. }
  64.  
  65. if ($linebreak === true) {
  66. // If we have found a line break then read the file into a string to writing without the last line.
  67. rewind($file_handle);
  68. $file_minus_lastline = fread($file_handle, $line_end);
  69.  
  70. // Close the file
  71. fclose($file_handle);
  72.  
  73. // Open the file in write mode and truncate it.
  74. $file_handle = fopen($filename, 'w+');
  75. fputs($file_handle, $file_minus_lastline);
  76. fclose($file_handle);
  77. } else {
  78. // Close the file, nothing else to do.
  79. fclose($file_handle);
  80. }

The script makes use of fseek() and ftell() to move backwards through the file in small increments. I have tested this with a few file sizes raging from a few kilobytes to over 100 megabytes and it works very quickly. Much faster than converting the file into an array.

Comments

Permalink
Okay... I followed what you are doing but I'm concerned about the statement:$file_minus_lastline = fread($file_handle, $line_end);If it is a huge file, then $file_minus_lastline could be very big also. Is that not true? Just thought I'd ask because I have a real need for this since I need to 'truncate' a very large file at a certain line. Thanks...

Andrea (Tue, 11/18/2014 - 01:48)

Add new comment

The content of this field is kept private and will not be shown publicly.