Remove The Last Line From A File In PHP

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

// Read the file into an array
$lines = file('file.txt');

// Pop the last item from the array 
array_pop($lines);

// Join the array back into a string
$file = join('', $lines);

// Write the string back into the file 
$file_handle = fopen('file.txt', 'w');
fputs($file_handle, $file);
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.

// Filename
$filename = 'file.txt';

// Open file
$file_handle = fopen($filename, 'r');

// Set up loop variables
$linebreak  = false;
$file_start = false;

// Number of bytes to look at
$bite = 50;

// File size
$filesize = filesize($filename);

// Put pointer to the end of the file.
fseek($file_handle, 0, SEEK_END);

while ($linebreak === false && $file_start === false) {
    // Get the current file position.
    $pos = ftell($file_handle);

    if ($pos < $bite) {
	// If the position is less than a bite then go to the start of the file
        rewind($file_handle);
    } else { 
        // Move back $bite characters into the file
        fseek($file_handle, -$bite, SEEK_CUR);
    }

    // Read $bite characters of the file into a string.
    $string = fread($file_handle, $bite) or die ("Can't read from file " . $filename . ".");

    /* If we happen to have read to the end of the file then we need to ignore 
     * the last line as this will be a new line character.
     */
    if ($pos + $bite >= $filesize) {
        $string = substr_replace($string, '', -1);
    }

    // Since we fred() forward into the file we need to back up $bite characters. 
    if ($pos < $bite) {
	// If the position is less than a bite then go to the start of the file
        rewind($file_handle);
    } else { 
        // Move back $bite characters into the file
        fseek($file_handle, -$bite, SEEK_CUR);
    }

    // Is there a line break in the string we read?
    if (is_integer($lb = strrpos($string, "\n"))) {
        // Set $linebreak to true so that we break out of the loop
        $linebreak = true;
        // The last line in the file is right after the linebreak
        $line_end = ftell($file_handle) + $lb + 1; 
    }

    if  (ftell($file_handle) == 0) {
       // Break out of the loop if we are at the beginning of the file. 
       $file_start = true;
    }
}

if ($linebreak === true) {
    // If we have found a line break then read the file into a string to writing without the last line.
    rewind($file_handle);
    $file_minus_lastline = fread($file_handle, $line_end);
    
    // Close the file
    fclose($file_handle);

    // Open the file in write mode and truncate it.
    $file_handle = fopen($filename, 'w+');
    fputs($file_handle, $file_minus_lastline);
    fclose($file_handle);
} else {
    // Close the file, nothing else to do.
    fclose($file_handle);
}

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

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...
Permalink

Add new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
9 + 0 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.