How to read and echo the N rows before the last row in TEXT file using PHP?
Example in file.txt
test1
test2
test3
test4
test5
test6
test7
I want to get the last row value and 3 row before last row.
So the result will be :
test4
test7
Here is my code so far (just show last row)
$line = '';
$f = fopen('\\\\192.168.183.28\\wk$\\sbin\\file.txt', 'r');
$cursor = -1;
fseek($f, $cursor, SEEK_END);
$char = fgetc($f);
while ($char === "\n" || $char === "\r") {
fseek($f, $cursor--, SEEK_END);
$char = fgetc($f);
}
while ($char !== false && $char !== "\n" && $char !== "\r")
{
$line = $char . $line;
fseek($f, $cursor--, SEEK_END);
$char = fgetc($f);
}
$future_sn = substr($line, 28, 36);
Any advice?
try
$array = explode("\n", file_get_contents('file.txt'));
// counting array and get key for prev
$prev_third = count($array)-4;
echo end($array); // test7
echo $array[$prev_third]; //test4
You can use fgets() to read file and keep a counter to keep track of last row. You can get 3 row ahead from last by mod(%) the counter.
$handle = fopen("input.txt", "r");
$lastRow = "";
$last3Ahead = "";
$counter = 0;
$a = "";
$b = "";
$c = "";
if ($handle) {
while (($line = fgets($handle)) !== false) {
if($counter == 0) $a = $line;
if($counter == 1) $b = $line;
if($counter == 2) $c = $line;
$lastRow = $line ;
if($counter >= 3) {
$last3Ahead = $a;
$a = $b;
$b = $c;
$c = $line
}
$counter++;
} else {
// error opening the file.
}
fclose($handle);
echo $lastRow. "<br>" ; //last row
echo $last3Ahead . "<br>"; //3 row before last;
Related
I have this text-file:
STATIONS_ID;MESS_DATUM; QN;PP_10;TT_10;TM5_10;RF_10;TD_10;eor
5371;201912250000; 2; 903.5; 2.3; 2.2; 100.0; 2.3;eor
[...]
5371;201912251820; 2; 913.3; 0.4; 0.3; 100.0; 0.4;eor
And I want to get ONLY the last line with timestamp 25-12-2019 18:20 (201912251820).
Thats my php code (finally I want to save the data in my MySQL database):
$row = 1;
if(($handle = fopen("produkt_zehn_now_tu_20191225_20191226_05371.txt", "r")) !== FALSE)
{
while(($data = fgetcsv($handle, 1000, ",")) !== FALSE)
{
echo "<p> 1 fields in line $row: <br /></p>\n";
$row++;
for($c=0; $c < 1; $c++)
{
echo $data[$c] . "<br />\n";
$daten = $data[$c];
$carray = explode(";", $daten);
list($station,$zeit,$quali,$luftdruck,$temp2m,$temp5cm,$feuchte,$taupunkt) = $carray;
echo "<b>temp2m:".$temp2m."</b>";
/*
$res_wetterdaten_dwd = $sql_datenbank -> query("INSERT INTO wetterdaten_dwd
(daten_zeit, daten_luftdruck, daten_temp2m, daten_temp5cm, daten_feuchte, daten_taupunkt, daten_station)
VALUES ('".$zeit."', ".$luftdruck.", ".$temp2m.", ".$temp5cm.", ".$feuchte.", ".$taupunkt.", ".$station.")");
*/
}
}
fclose($handle);
}
<?php
function getDateFromFile($file = 'text.txt')
{
$f = fopen($file, 'r');
$cursor = -1;
$line = '';
fseek($f, $cursor, SEEK_END);
$char = fgetc($f);
/**
* Trim trailing newline chars of the file
*/
while ($char === "\n" || $char === "\r") {
fseek($f, $cursor--, SEEK_END);
$char = fgetc($f);
}
/**
* Read until the start of file or first newline char
*/
while ($char !== false && $char !== "\n" && $char !== "\r") {
/**
* Prepend the new char
*/
$line = $char . $line;
fseek($f, $cursor--, SEEK_END);
$char = fgetc($f);
}
$value = explode(";", $line);
$year = substr($value[1], 0, 4);
$month = substr($value[1], 4, 2);
$day = substr($value[1], 6, 2);
$hour = substr($value[1], 8, 2);
$min = substr($value[1], 10, 2);
$date = new DateTime("$year-$month-$day $hour:$min");`
return $date;
}
print_r(getDateFromFile("produkt_zehn_now_tu_20191225_20191226_05371.txt"));
I'm trying to get using only fopen() and fseek() to get specific lines of code (not only one lines, i need to get line above and below of current seek line).
To improve performance, I know how to get specific line to seek and then exit. If I need line 5 then should be get seekable into 4 and 6.
Here is a code to get bytes of each lines then put into array as lines as key and value as bytes to EOF.
$fh = fopen($source, 'r');
$meta = stream_get_meta_data($fh);
if (!$meta['seekable']) {
throw new Exception(sprintf("A source is not seekable: %s", print_r($source, true)));
}
$line = fgets($fh, 4096);
$pos = -1;
$i = 0;
$result = null;
$linenum = 10;
var_dump('Line num:'.$linenum);
$total_lines = null;
// Get seek byte end of each line
while (!feof($fh)) {
$char = fgetc($fh);
if ($char != "\n" && $char != "\r") {
$total_lines[$i] = $pos;
$pos++;
} else {
$i++;
}
//var_dump(fgets($fh).' _ '.$pos);
}
// Now get specific lines (line 5, line 6 and line 7)
$seekssearch = array($total_lines[5], $total_lines[6], $total_lines[7]);
$result = null;
$posr = 0;
foreach ($seekssearch as $sk) {
while (!feof($fh)) {
if ($char != "\n" && $char != "\r") {
fseek($fh, $sk, SEEK_SET);
$posr++;
} else {
$ir++;
}
}
// Merge result of line 5,6 and 7
$result .= fgets($fh);
}
echo $result;
exit;
while (!feof($fh) && $i<($linenum)) {
$char = fgetc($fh);
if ($char != "\n" && $char != "\r") {
fseek($fh, $pos, SEEK_SET);
$pos++;
}
else {
$i++;
}
}
$line = trim(fgets($fh));
var_dump($line);
exit;
exit;
while (!feof($fh) && $i<($linenum-1)) {
$char = fgetc($fh);
if ($char != "\n" && $char != "\r") {
//fseek($fh, $pos);
fseek($fh, $pos);
$pos++;
}
else {
if ($pos == 3) {
$line = fgets($fh);
}
$i++;
}
}
//$line = fgets($fh);
var_dump($line); exit;
How to merge this lines?
Note: I don't want using splFileInfo or any tricks like arrays. Just want to seek then exit.
I've created a function that read a file and count lines and store into arrays each lines bytes to seek. If maximum specified by linenum is set, it will break from while to keep performance than in a new loop function to seek a position in bytes to get a content of file.
I believe that can this function improve.
function readFileSeek($source, $linenum = 0, $range = 0)
{
$fh = fopen($source, 'r');
$meta = stream_get_meta_data($fh);
if (!$meta['seekable']) {
throw new Exception(sprintf("A source is not seekable: %s", print_r($source, true)));
}
$pos = 2;
$result = null;
if ($linenum) {
$minline = $linenum - $range - 1;
$maxline = $minline+$range+$range;
}
$totalLines = 0;
while (!feof($fh)) {
$char = fgetc($fh);
if ($char == "\n" || $char == "\r") {
++$totalLines;
} else {
$result[$totalLines] = $pos;
}
$pos++;
if ($maxline+1 == $totalLines) {
// break from while to not read entire file
break;
}
}
$buffer = '';
for ($nr=$minline; $nr<=$maxline; $nr++) {
if (isset($result[$nr])) {
fseek($fh, $result[$nr], SEEK_SET);
while (!feof($fh)) {
$char = fgetc($fh);
if ($char == "\n" || $char == "\r") {
$buffer .= $char;
break;
} else {
$buffer .= $char;
}
}
}
}
return $buffer;
}
Test results (1.3 GB file, 100000000 lines of codes, seek to 300000 line a code):
string(55) "299998_abc
299999_abc
300000_abc
300001_abc
300002_abc
"
Time: 612 ms, Memory: 20.00Mb
$ ll -h /tmp/testReadSourceLines_27151460344/41340913936
-rw-rw-r-- 1 1,3G /tmp/testReadSourceLines_27151460344/41340913936
I have text file
name,name1
willhaveishere1
name,name2
willhaveishere2
name,name3
willhaveishere3
i want read it and return like that
$nn = name1
$ss = willhaveishere1
with my code i get only name1
my code is
$file1 = "file.txt";
$file = file($file1);
$count = count($file);
if($count > 0) {
$i = 1;
foreach($file as $row) {
$n = strstr($row, 'name,');
$cc = array("name,");
$dd = array("");
$nn = str_replace($cc, $dd, $n);
echo $nn;
$i++; } }
This is probably what you need
if($count > 0) {
foreach($file as $row) {
$pos = strpos($row, ',');
if($pos !== false){
echo substr($row, $pos + 1);
$nn[] = substr($row, $pos + 1);
} else {
echo $row;
$ss[] = $row;
}
}
}
EDIT
Yes, just loop through, but make sure both $nn and $ss has same count, which is depending on your file.
Also Note: mysql_* functions has been deprecated, so please use mysqli or PDO instead
$count = count($nn);
for($i=0; $i < $count; $i++){
$sql = "INSERT INTO users(name, line) VALUES('$nn[$i]', '$ss[$i]')"; mysql_query($sql);
}
EDIT 2
try this example:
$file = array(
0 => 'name,name1',
1 => 'willhaveishere1',
2 => 'name,name2',
3 => 'willhaveishere2',
4 => 'name,name3',
5 => 'willhaveishere3'
);
$count = count($file);
if($count > 0) {
foreach($file as $row) {
$pos = strpos($row, ',');
if($pos !== false){
$nn[] = substr($row, $pos + 1);
} else {
$ss[] = $row;
}
}
}
echo '<pre>';
$count = count($nn);
for($i=0; $i < $count; $i++){
$sql = "INSERT INTO users(name, line) VALUES('$nn[$i]', '$ss[$i]');";
echo $sql.PHP_EOL;
}
You can try this straightforward method:
if($fh = fopen("file.txt","r")){
$nameBefore = false;
//loop through every line of your file
while (!feof($fh)){
$line = fgets($fh);
//check if the name was detected in previous line
if ($nameBefore !== false)
{
//you have the set of name and line, do what you want
echo $nameBefore . ': ' . $line . '<br />';
$nameBefore = false;
}
else
{
//see if the line is made of two coma separated segments and the first one is 'name'
//Remember the name for the next line
$parts = explode(',', $line);
if (count($parts) == 2 && $parts[0] == 'name')
$nameBefore = $parts[1];
}
}
fclose($fh);
}
One option is to use strpos to find the first occurrence of the character in the line, and if found remove everything from the line before that position. This way you are left with only the part of the line you are interested in.
Code:
$character = ',';
$fileHandle = fopen('file.txt', 'r');
while (!feof($fileHandle)) {
// Retrieve the line from the file
$line = fgets($fileHandle);
// If the line contains the character
// Remove everything before the character
$charPos = strpos($line, $character);
if ($charPos !== false) {
$line = substr($line, $charPos + 1);
}
// Do something with the remainder of the line
echo $line . PHP_EOL;
}
fclose($fileHandle);
Output:
name1
willhaveishere1
name2
willhaveishere2
name3
willhaveishere3
If you wish to retrieve the following line, simply do another retrieve line call in your loop:
while (!feof($fileHandle)) {
// Retrieve two lines in one loop iteration
$lineOne = fgets($fileHandle);
$lineTwo = fgets($fileHandle);
}
Making sure to only apply the comma replace part on the first line. This can lead to problems though if your data is... inconsistent.
Hope this helps.
So far I'm able to return the entire file, or an empty string. But not the first n lines of a file as expected.
echo head('/path/to/my_file.txt',100); // returns '', or in other versions `1\n1\n...`
function head($filepath, $lines = 1, $adaptive = true) {
// Open file
$f = #fopen($filepath, "rb");
if ($f === false) return false;
// Sets buffer size
if (!$adaptive) $buffer = 4096;
else $buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096));
// Start reading
$output = '';
while($line = fgets($f,$buffer) !== false) {
if (feof($f)) break;
$output .= $line . "\n";
}
// Close file and return
fclose($f);
return trim($output);
}
In contrast, the following tail function (source) works perfectly:
function tail($filepath, $lines = 1, $adaptive = true) {
// Open file
$f = #fopen($filepath, "rb");
if ($f === false) return false;
// Sets buffer size
if (!$adaptive) $buffer = 4096;
else $buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096));
// Jump to last character
fseek($f, -1, SEEK_END);
// Read it and adjust line number if necessary
// (Otherwise the result would be wrong if file doesn't end with a blank line)
if (fread($f, 1) != "\n") $lines -= 1;
// Start reading
$output = '';
$chunk = '';
// While we would like more
while (ftell($f) > 0 && $lines >= 0) {
// Figure out how far back we should jump
$seek = min(ftell($f), $buffer);
// Do the jump (backwards, relative to where we are)
fseek($f, -$seek, SEEK_CUR);
// Read a chunk and prepend it to our output
$output = ($chunk = fread($f, $seek)) . $output;
// Jump back to where we started reading
fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR);
// Decrease our line counter
$lines -= substr_count($chunk, "\n");
}
// While we have too many lines
// (Because of buffer size we might have read too many)
while ($lines++ < 0) {
// Find first newline and remove all text before that
$output = substr($output, strpos($output, "\n") + 1);
}
// Close file and return
fclose($f);
return trim($output);
}
// here the correction => apply parenthesis before ...
while(($line = fgets($f)) !== false) {
if (feof($f)) break;
if ($lines-- == 0) break;
$output .= $line . "\n";
}
You just need to keep a count of the number of lines read, and abort after $lines is reached.
$i = 0;
while($line = fgets($file) !== false) {
if (feof($file)) break;
$output .= $line . "\n";
if ($i++ >= $lines) {
break;
}
}
I'm guessing it's fgets, but I can't find the specific syntax. I'm trying to read out (in a string I'm thinking is easier) the last line added to a log file.
The simplest naive solution is simply:
$file = "/path/to/file";
$data = file($file);
$line = $data[count($data)-1];
Though, this WILL load the whole file into memory. Possibly a problem (or not). A better solution is this:
$file = escapeshellarg($file); // for the security concious (should be everyone!)
$line = `tail -n 1 $file`;
This looks like it is what you are looking for:
tekkie.flashbit.net: Tail functionality in PHP
It implements a function that uses fseek() with a negative index to roll up the file from the end. You can define how many lines you want to be returned.
The code also is available as a Gist on GitHub:
// full path to text file
define("TEXT_FILE", "/home/www/default-error.log");
// number of lines to read from the end of file
define("LINES_COUNT", 10);
function read_file($file, $lines) {
//global $fsize;
$handle = fopen($file, "r");
$linecounter = $lines;
$pos = -2;
$beginning = false;
$text = array();
while ($linecounter > 0) {
$t = " ";
while ($t != "\n") {
if(fseek($handle, $pos, SEEK_END) == -1) {
$beginning = true;
break;
}
$t = fgetc($handle);
$pos --;
}
$linecounter --;
if ($beginning) {
rewind($handle);
}
$text[$lines-$linecounter-1] = fgets($handle);
if ($beginning) break;
}
fclose ($handle);
return array_reverse($text);
}
$fsize = round(filesize(TEXT_FILE)/1024/1024,2);
echo "<strong>".TEXT_FILE."</strong>\n\n";
echo "File size is {$fsize} megabytes\n\n";
echo "Last ".LINES_COUNT." lines of the file:\n\n";
$lines = read_file(TEXT_FILE, LINES_COUNT);
foreach ($lines as $line) {
echo $line;
}
define('YOUR_EOL', "\n");
$fp = fopen('yourfile.txt', 'r');
$pos = -1; $line = ''; $c = '';
do {
$line = $c . $line;
fseek($fp, $pos--, SEEK_END);
$c = fgetc($fp);
} while ($c != YOUR_EOL);
echo $line;
fclose($fp);
This is better, since it does not load the complete file into memory...
Set YOUR_EOL to your correct line endings, if you use the same line endings as the default line endings of the OS where your script resides, you could use the constant PHP_EOL.
function seekLastLine($f) {
$pos = -2;
do {
fseek($f, $pos--, SEEK_END);
$ch = fgetc($f);
} while ($ch != "\n");
}
-2 because last char can be \n
You either have to read the file in line by line and save the last read line to get it.
Or if on unix/linux you might consider using the shell command tail
tail -n 1 filename
This one wont break for a 1 or 0 line file.
function readlastline($fileName)
{
$fp = #fopen($fileName, "r");
$begining = fseek($fp, 0);
$pos = -1;
$t = " ";
while ($t != "\n") {
fseek($fp, $pos, SEEK_END);
if(ftell($fp) == $begining){
break;
}
$t = fgetc($fp);
$pos = $pos - 1;
}
$t = fgets($fp);
fclose($fp);
return $t;
}
If you want to read a file line by line the file function reads the contents of a file, line by line and returns each line as an element of an array.
So you could do something simple like:
$lines = file('log.txt');
$lastLine = array_pop($lines);
...Why just read the last line?
function readLines($fp, $num) {
$line_count = 0; $line = ''; $pos = -1; $lines = array(); $c = '';
while($line_count < $num) {
$line = $c . $line;
fseek($fp, $pos--, SEEK_END);
$c = fgetc($fp);
if($c == "\n") { $line_count++; $lines[] = $line; $line = ''; $c = ''; }
}
return $lines;
}
$filename = "content.txt";
$fp = #fopen($filename, "r");
print_r(readLines($fp, 2));
fclose($fp);
#unique_stephen, your answer is flawed. PHP fseek returns 0 for success and -1 for failure. Storing the result in $begining (sic) and then later using it in a filter for ftell() isn't correct. If my reputation were higher I would have voted you down and left a comment. Here is a modified version of unique_stephen's function.
function readlastline($fileName)
{
$fp = #fopen($fileName, "r");
if (fseek($fp, 0) == -1)
exit('Cannot seek to beginning of the file');
$pos = -1;
$t = " ";
while ($t != "\n") {
if (fseek($fp, $pos, SEEK_END) == -1)
exit('Cannot seek to the end of the file');
if (ftell($fp) == 0) {
break;
}
$t = fgetc($fp);
$pos = $pos - 1;
}
$t = fgets($fp);
fclose($fp);
return $t;
}
NOTE: PHP's fseek cannot manage to seek to the end of files larger than PHP_MAX_INT which is 32bit signed even on 64bit binaries.
function readlastline($fileName)
{
$fp = #fopen($fileName, "r");
$begining = fseek($fp, 0);
$pos = -1;
$t = " ";
while ($t != "\n") {
fseek($fp, $pos, SEEK_END);
if(ftell($fp) == $begining){
break;
}
$t = fgetc($fp);
$pos = $pos - 1;
}
$t = fgets($fp);
fclose($fp);
return $t;
}