How to put a limit for writing in a file, if it hit the limit then remove the last line..
As example here's a file:
Line 3
Line 2
Line 1
i want to max line it for 3 lines only.. so when i write a new line using any append functions it removes the last line.. Let's say i just wrote a new line ( Line 4 ).. so it goes to the last one and remove it, result should be :
Line 4
Line 3
Line 2
And for a new written line (Line 5):
Line 5
Line 4
Line 3
numeric lines is not required, i just want to remove the last line if there's a new added line via an append functions (file_put_contents / fwrite) and max it by 3 or a specific number i give
You can try
$max = 3;
$file = "log.txt";
addNew($file, "New Line at : " . time());
Function Used
function addNew($fileName, $line, $max = 3) {
// Remove Empty Spaces
$file = array_filter(array_map("trim", file($fileName)));
// Make Sure you always have maximum number of lines
$file = array_slice($file, 0, $max);
// Remove any extra line
count($file) >= $max and array_shift($file);
// Add new Line
array_push($file, $line);
// Save Result
file_put_contents($fileName, implode(PHP_EOL, array_filter($file)));
}
Here's one way:
Use file() to read the file's lines into an array
Use count() to determine if there's more than 3 elements in the array. If so:
Remove the last element of the array with array_pop()
Use array_unshift() to add an element (the new line) to the front of the array
Overwrite the file with the lines of the array
Example:
$file_name = 'file.txt';
$max_lines = 3; #maximum number of lines you want the file to have
$new_line = 'Line 4'; #content of the new line to add to the file
$file_lines = file($file_name); #read the file's lines into an array
#remove elements (lines) from the end of the
#array until there's one less than $max_lines
while(count($file_lines) >= $max_lines) {
#remove the last line from the array
array_pop($file_lines);
}
#add the new line to the front of the array
array_unshift($file_lines, $new_line);
#write the lines to the file
$fp = fopen($file_name, 'w'); #'w' to overwrite the file
fwrite($fp, implode('', $file_lines));
fclose($fp);
Try this.
<?php
// load the data and delete the line from the array
$lines = file('filename.txt');
$last = sizeof($lines) - 1 ;
unset($lines[$last]);
// write the new data to the file
$fp = fopen('filename.txt', 'w');
fwrite($fp, implode('', $lines));
fclose($fp);
?>
Modified from Baba's answer; this code will write the new line at the beginning of the file and will errase the last one to keep always 3 lines.
<?php
function addNew($fileName, $line, $max) {
// Remove Empty Spaces
$file = array_filter(array_map("trim", file($fileName)));
// Make Sure you always have maximum number of lines
$file = array_slice($file, 0, --$max);
// Remove any extra line and adding the new line
count($file) >= $max and array_unshift($file, $line);
// Save Result
file_put_contents($fileName, implode(PHP_EOL, array_filter($file)));
}
// Number of lines
$max = 3;
// The file must exist with at least 2 lines on it
$file = "log.txt";
addNew($file, "New Line at : " . time(), $max);
?>
Related
I have a text file like this:
1
2
3
4
5
6
7
8
9
10
And I want to remove specific lines which numbers are in an array like this:
$myfile='txt.txt';
$remove=array(1,3,6,7,10);
//wanna remove these lines
So I tried this code but It didn't work and It just doubles the text and ruins everything:
<?php
$myfile='txt.txt';
$remove=array(1,3,5,7,10);
$lines=file($myfile);
$countline=sizeof($lines);
$data=file_get_contents($myfile);
for ($i=0; $i < $countline+1; $i++) {
if (in_array($i, $remove)) {
$editeddata=str_replace($lines[$i], "", $data);
$removeline = file_put_contents($myfile, $editeddata.PHP_EOL , FILE_APPEND | LOCK_EX);
}
}
?>
I couldn't use ((for)) properly and I think it will just ruin the text because it deletes lines one after another have been deleted and it changes the order so I should have a code to remove them all at once.
And please don't give a code to just replace numbers because the main text file is not only numbers and contains word,etc...
Thanks A lot!
You're reading the file twice (with file and file_get_contents), which I think is confusing the later code. You have everything you need with the first call - an array of all the lines in the file. You're also using str_replace to remove the content, which seems a bit dangerous if any of the content is repeated.
I'd refactor this to simply filter the array of lines based on their line-number, then write it back to the file in a single operation:
$myfile = 'txt.txt';
$remove = [1, 3, 5, 7, 10];
// Read file into memory
$lines = file($myfile);
// Filter lines based on line number (+1 because the array is zero-indexed)
$lines = array_filter($lines, function($lineNumber) use ($remove) {
return !in_array($lineNumber + 1, $remove);
}, ARRAY_FILTER_USE_KEY);
// Re-assemble the output (the lines already have a line-break at the end)
$output = implode('', $lines);
// Write back to file
file_put_contents($myfile, $output);
If the file fits in memory then you can do the simple:
$myfile='txt.txt';
$remove=array(1,3,6,7,10);
file_put_contents($myfile, implode(PHP_EOL,array_diff($file($myfile,FILE_IGNORE_NEW_LINES), $remove)));
Note: Because it's a bit ambiguous whether $remove has the content or the lines you want to remove, the above code removes the content . If you want to remove lines change array_diff($file($myfile,FILE_IGNORE_NEW_LINES), $remove) to array_diff_keys($file($myfile,FILE_IGNORE_NEW_LINES), array_flip($remove))
If your file is large then you need to resort to some sort of streaming. I suggest against reading and writing to the same file and doing something like:
$myfile='txt.txt';
$remove=array(1,3,6,7,10);
$h = fopen($myfile,"r");
$tmp = fopen($myfile.".tmp", "w");
while (($line = fgets($h)) !== false) {
if (!in_array(rtrim($line, PHP_EOL), $remove)) {
fwrite($tmp, $line);
}
}
fclose($h);
fclose($tmp);
unlink($myfile);
rename($myfile.".tmp", $myfile);
I have a file like some.txt having content :
#start-first
Line 1
Line 2
Line 3
#end-first
#start-second
Line 1
Line 2
Line 3
Line 4
#end-second
#start-n
Line 1
Line 2
Line 3
Line 4
...
...
#end-n
I want to delete content from file from #start-second to #end-second or from #start-n to #end-n, actually #start-second is Start Marker for Second Text Block of file and #end-second is End Marker for Second Text Block of file.
How to delete content from Specific Start Block to same End block ?
If these files are really big, there is a fairly lightweight solution:
$file = file_get_contents("example.txt");
// Find the start "#start-$block", "#end-$block" and the length between them:
$start = strpos($file, "#start-$block");
$end = strpos($file, "#end-$block");
$length = $end-$start+strlen("#end-$block");
$file = substr_replace($file, '', $start, length);
file_put_contents("example.txt", $file);
My original answer started with a regex:
$block = 4;
// Open the file
$file = openfile("example.txt");
// replace #start-$block, #end-$block, and everything inbetween with ''
$file = preg_replace("/#start\-".$block."(?:.*?)#end\-".$block."/s", '', $file);
// Save the changes
file_put_contents("example.txt", $file);
Regexes are expensive though, but sometimes easier to understand.
Here is my solution:
It's a bit more difficult to do it line by line, but it does let you manage memory better for large files, because your not opening the entire file all at once. Also you can replace multiple blocks a bit easier this way.
$file = 'test.txt';
//open file to read from
$f = fopen(__DIR__.DIRECTORY_SEPARATOR.$file,'r');
//open file to write to
$w = fopen(__DIR__.DIRECTORY_SEPARATOR.'out-'.$file,'w');
$state = 'start'; //start, middle, end
//start - write while looking for a start tag ( set to middle )
//middle - skip while looking for end tag ( set to end )
//end - skip while empty ( set to start when not )
//Tags
$start = ['#start-second'];
$end = ['#end-second'];
//read each line from the file
while( $line = fgets($f)){
if( $state == 'end' && !empty(trim($line))){
//set to start on first non empty line after tag
$state = 'start';
}
if( $state == 'start' ){
if(in_array(trim($line),$start)){
$state = 'middle';
}else{
fwrite($w, $line);
}
}else if( $state == 'middle' ){
if(in_array(trim($line),$end)){
$state = 'end';
}
}
}
//close both files
fclose($f);
fclose($w);
//delete the input file
//unlink(__DIR__.DIRECTORY_SEPARATOR.$file);
//for debugging only
echo "<pre>";
echo file_get_contents(__DIR__.DIRECTORY_SEPARATOR.'out-'.$file)
And the output
#start-first
Line 1
Line 2
Line 3
#end-first
#start-n
Line 1
Line 2
Line 3
Line 4
...
...
#end-n
This will also accept an array of tags, so you can remove multiple chunks per go.
Most the PHP sandboxes ( or code sandboxes in general ) prevent you from using the functions, for security reasons. That said, we can emulate the body of the code, the parsing bit, to some extent. So that is what I have done here.
http://sandbox.onlinephpfunctions.com/code/0a746fb79041d30fcbddd5bcb00237fcdd8eea2f
That way you can try a few different tags and see how it works. For extra credit you could make this into a function that accepts the filepath and an array of open and start tags.
/**
* #var string $pathName - full path to input file
* #var string $outputName - name of output file
* #var array $tags - array of tags ex. ['start'=>['tag1'],'end'=>[...]]
* #return string - path to output file
*/
function($pathName, $outputName, array $tags){
....
}
I am working on reading a file in php.
I need to read specific lines of the file.
I used this code:
fseek($file_handle,$start);
while (!feof($file_handle))
{
///Get and read the line of the file pointed at.
$line = fgets($file_handle);
$lineArray .= $line."LINE_SEPARATOR";
processLine($lineArray, $linecount, $logger, $xmlReply);
$counter++;
}
fclose($file_handle);
However I realized that the fseek() takes the number of bytes and not the line number.
Does PHP have other function that bases its pointer in line numbers?
Or do I have to read the file from the start every time, and have a
counter until my desired line number is read?
I'm looking for an efficient algorithm, stepping over 500-1000 Kb file to get to the desired line seems inefficient.
Use SplFileObject::seek
$file = new SplFileObject('yourfile.txt');
$file->seek(123); // seek to line 124 (0-based)
Does this work for you?
$file = "name-of-my-file.txt";
$lines = file( $file );
echo $lines[67]; // echos line 68 (lines numbers start at 0 (replace 68 with whatever))
You would obviously need to check the lines exists before printing though. Any good?
You could do like:
$lines = file($filename); //file in to an array
echo $lines[1]; //line 2
OR
$line = 0;
$fh = fopen($myFile, 'r');
while (($buffer = fgets($fh)) !== FALSE) {
if ($line == 1) {
// $buffer is the second line.
break;
}
$line++;
}
You must read from the beginning. But if the file never/rarely changes, you could cache the line offsets somewhere else, perhaps in another file.
Try this,the simplest one
$buffer=explode("\n",file_get_contents("filename"));//Split data to array for each "\n"
Now the buffer is an array and each array index contain each lines;
To get the 5th line
echo $buffer[4];
You could use function file($filename) . This function reads data from the file into array.
I am trying add HTML to a file using fwrite(). My final goal is to get it to add it 15 lines above the end of the file. Here is what I have so far:
<?php
$file = fopen("index.html", "r+");
// Seek to the end
fseek($file, SEEK_END, 0);
// Get and save that position
$filesize = ftell($file);
// Seek to half the length of the file
fseek($file, SEEK_SET, $filesize + 15);
// Write your data
$main = <<<MAIN
//html goes here
MAIN;
fwrite($file, $main);
// Close the file handler
fclose($file);
?>
This just keeps overwriting the top of the file.
Thanks.
The sample code in the question does not operate based on lines, since you're working with file size (unless there is an assumption about definition of lines in the application that is not mentioned in here). If you want to work with lines, then you'd need to search for new line characters (which separates each line with the next).
If the target file is not a large file (so we could load the whole file into memory), we could use PHP built-in file() to read all the lines of the file into an array, and then insert the data after the 15th element. something like this:
<?php
$lines = file($filename);
$num_lines = count($lines);
if ($num_lines > 15) {
array_splice($lines, $num_lines - 15, 0, array($content));
file_put_contents($filename, implode('', $lines));
} else {
file_put_contents($filename, PHP_EOL . $content, FILE_APPEND);
}
I use append code to write new lines in .txt file:
$fh = fopen('ids.txt', 'a');
fwrite($fh, "Some ID\n");
fclose($fh);
I want this file to have only 20 lines and delete the first (old) ones.
Read all the lines in, add your lines at the bottom, then rewrite the file with only the last 20 lines.
I am not great at php, but if you only want 20 lines surely you would do something like this pseudocode.
lines <- number of lines you want to write
if lines > 20
yourfile <- new file
yourfile.append (last 20 lines of your text)
else if lines = 20
your file <- new file
yourfile.append (your text)
else
remainingtext <- the last [20-lines] of yourfile
yourfile.append (remaining text + your text)
EDIT: an easier way of doing it, but perhaps less efficient [I think this is equivalent to NovaDenizen's solution]
yourfile <- your file
yourfile.append(yourtext)
newfilearray <- yourfile.tokenize(newline)(http://php.net/manual/en/function.explode.php)
yourfile <- newfile
for loop from i=newfilearray.size-21 < newfilearray.size
yourfile.append (newfilearray[i])
$content=file($filename);
$content[]='new line of content';
$content[]='another new line of content';
$file_content=array_slice($content,-20,20);
$file_content=implode("\n",$file_content);
file_put_contents($filename,$file_content);
You can us file() function to load file as an array. Then add new content to loaded array, slice it to 20 elements, make 'entered' text from this array and save it to a file.
You could make use of the function file:
http://php.net/manual/en/function.file.php
Reads an entire file into an array.
This said, you Need to do the following:
1.) Read the existing file into an Array:
$myArray= file("PathToMyFile.txt");
2.) Reverse the Array, so the oldest Entry is topmost:
$myArray= array_reverse($myArray);
3.) Add your NEW Entry to the end of that Array.
$myArray[] = $newEntry + "\n";
4.) Reverse it again:
$myArray= array_reverse($myArray);
5.) Write the first 20 Lines back to your file (this is your "new" + 19 old lines):
$i = 1;
$handle = fopen("PathToMyFile.txt", "w"); //w = create or start from bit 0
foreach ($myArray AS $line){
fwrite($handle, $line); //line end is NOT removed by file();
if ($i++ == 20){
break;
}
}
fclose($handle);
Why dont you just use file_put_contents("yourfile.txt", ""); to set the file contents to nothing and then just file_put_contents("yourfile.txt",$newContent)?
Are you trying to do something else or am I missing something?