Note: This post is over two years old and so the information contained here might be out of date. If you do spot something please leave a comment and we will endeavour to correct.
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.
// 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.
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...
If you've ever looked at the settings in a digital camera, or have experience with image processing programs like GIMP, then you may have seen a colour histogram. This is a simple graph that shows the amount of different shades of colour are present in the image.
I was writing unit tests for a API mapping function recently and came across this interesting issue. The code I was writing tests for was in a legacy codebase that I was making changes to, and it made sense to have some unit tests in there before I started work to ensure everything worked before and after.
Embedding image within pages of content helps both within the design of the page and when shared on social media. If you set up meta tags to point at a particular image then that image will appear when the page is shared on social media. This makes your page stand out more.
Generating a PDF document from a web page through PHP can be problematic. It's often something that seems quite simple, but actually generating the document can be difficult and time consuming.
Comments
$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...Submitted by Andrea on Tue, 11/18/2014 - 01:48
PermalinkAdd new comment