Прочитать последнюю строку из файла

Я столкнулся с проблемой. У меня есть журнал в ящике Linux, в котором записывается вывод нескольких запущенных процессов. Иногда этот файл может стать действительно большим, и мне нужно прочитать последнюю строку из этого файла.

Проблема в том, что это действие будет вызвано через запрос AJAX довольно часто, и когда размер файла этого журнала превысит 5-6 МБ, это не очень хорошо для сервера. Поэтому я думаю, что мне нужно прочитать последнюю строку, но не прочитать весь файл и не передать его или загрузить в ОЗУ, потому что это будет просто загружать мою коробку.

Есть ли какая-либо оптимизация для этой операции, чтобы она работала плавно, а не вредить серверу или убивать Apache?

Другой вариант, который у меня есть, – exec('tail -n 1 /path/to/log') но это звучит не так хорошо.

Позже отредактируйте: я НЕ хочу помещать файл в ОЗУ, потому что он может стать огромным. fopen() не является опцией.

Solutions Collecting From Web of "Прочитать последнюю строку из файла"

Это должно работать:

 $line = ''; $f = fopen('data.txt', 'r'); $cursor = -1; 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); } echo $line; 

Используйте fseek . Вы пытаетесь найти последнюю позицию и искать ее назад (используйте ftell для указания текущей позиции), пока не найдете «\ n».

 $fp = fopen("....."); fseek($fp, -1, SEEK_END); $pos = ftell($fp); $LastLine = ""; // Loop backword util "\n" is found. while((($C = fgetc($fp)) != "\n") && ($pos > 0)) { $LastLine = $C.$LastLine; fseek($fp, $pos--); } 

ПРИМЕЧАНИЕ. Я не тестировал. Возможно, вам потребуется корректировка.

UPDATE: Спасибо Syntax Error для указания на пустой файл.

😀

UPDATE2: Исправлена ​​ошибка синтаксиса, отсутствовала точка с запятой в $LastLine = ""

Вы ищете функцию fseek . Существуют рабочие примеры того, как читать последнюю строку файла в разделе комментариев.

Если вы знаете верхнюю границу длины строки, вы можете сделать что-то подобное.

 $maxLength = 1024; $fp = fopen('somefile.txt', 'r'); fseek($fp, -$maxLength , SEEK_END); $fewLines = explode("\n", fgets($fp, $maxLength)); $lastLine = $fewLines[count($fewLines) - 1]; 

В ответ на редактирование : fopen просто получает дескриптор файла (т. Е. Убедитесь, что он существует, процесс имеет разрешение, позволяет os знать, что процесс использует файл и т. Д.). В этом примере в память будет считываться только 1024 символа из файла.

 function readlastline() { $fp = @fopen("/dosmnt/LOGFILE.DAT", "r"); $pos = -1; $t = " "; while ($t != "\n") { fseek($fp, $pos, SEEK_END); $t = fgetc($fp); $pos = $pos - 1; } $t = fgets($fp); fclose($fp); return $t; } 

Источник: http://forums.devshed.com/php-development-5/php-quick-way-to-read-last-line-156010.html

это код Ионуца Г. Стэна

я немного изменил ваш код и сделал его функцией для повторного использования

 function read_last_line ($file_path){ $line = ''; $f = fopen($file_path, 'r'); $cursor = -1; 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); } return $line; } 

echo read_last_line ('log.txt');

вы получите эту последнюю строку

Ваша проблема похожа на эту

Лучший способ избежать загрузки всего файла в память выглядит следующим образом:

 $file = escapeshellarg($file); // for the security concious (should be everyone!) $line = `tail -n 1 $file`; 

Можно ли было бы оптимизировать это с другой стороны? Если это так, просто пусть приложение регистрации всегда регистрирует строку в файле при ее усечении (т.е.> вместо >>)

Некоторая оптимизация может быть достигнута путем «угадывания», хотя, просто откройте файл и со средней шириной строки журнала, которую вы могли бы догадаться, где будет последняя строка. Перейдите в эту позицию с помощью fseek и найдите последнюю строку.

Неподтвержденный код из комментариев http://php.net/manual/en/function.fseek.php

 jim at lfchosting dot com 05-Nov-2003 02:03 Here is a function that returns the last line of a file. This should be quicker than reading the whole file till you get to the last line. If you want to speed it up a bit, you can set the $pos = some number that is just greater than the line length. The files I was dealing with were various lengths, so this worked for me. <?php function readlastline($file) { $fp = @fopen($file, "r"); $pos = -1; $t = " "; while ($t != "\n") { fseek($fp, $pos, SEEK_END); $t = fgetc($fp); $pos = $pos - 1; } $t = fgets($fp); fclose($fp); return $t; } ?> 

Это мое решение только с одним циклом

  $line = ''; $f = fopen($file_path, 'r'); $cursor = 0 ; do { fseek($f, $cursor--, SEEK_END); $char = fgetc($f); $line = $char.$line; } while ( $cursor > -1 || ( ord($char) !== 10 && ord($char) !== 13 ) ); 

Ниже приведена компиляция ответов, заключенных в функцию, которая может указывать, сколько строк должно быть возвращено.

 function getLastLines($path, $totalLines) { $lines = array(); $fp = fopen($path, 'r'); fseek($fp, -1, SEEK_END); $pos = ftell($fp); $lastLine = ""; // Loop backword until we have our lines or we reach the start while($pos > 0 && count($lines) < $totalLines) { $C = fgetc($fp); if($C == "\n") { // skip empty lines if(trim($lastLine) != "") { $lines[] = $lastLine; } $lastLine = ''; } else { $lastLine = $C.$lastLine; } fseek($fp, $pos--); } $lines = array_reverse($lines); return $lines; } 

Я бы использовал файл (), который считывает файл в массив, реверсирует массив и получает первый элемент или всплывает массив:

$ last_line = array_pop (файл ($ filename));

Если вы хотите, чтобы производительность попыталась открыть файл и с помощью указателя файла перейти на него.