Intereting Posts
Что я должен использовать для аутентификации пользователей в PHP? PDO Невозможно выполнить запросы, в то время как другие небуферизованные запросы активны Как читать карту в веб-приложении php, написанном с использованием Boost C ++ (в общей области)? Вытяните столбцы из производной таблицы и суммируйте их в одном выражении SELECT MySQL если curl getinfo для HTTP CODE не возвращает код? Как отправить запрос POST с PHP? Разбор SELECT предложения SQL-запросов в массив PHP Удаление предупреждающих сообщений в PHP jQuery / PHP mail отправляет простой способ? SQL – вставка формы в базу данных Встраивание видео в YouTube «Отказано от отображения документа, потому что отображение запрещено с помощью X-Frame-Options» подтверждение сообщения перед отправкой в ​​php проверьте вручную для jpeg конца маркера файла ffd9 (?) в php, чтобы поймать ошибки усечения Каков синтаксис сортировки коллекции Eloquent несколькими столбцами? Регистрационный код PHP

Чтение больших файлов с конца

Могу ли я прочитать файл в PHP с моего конца, например, если я хочу прочитать последние 10-20 строк?

И, как я читал, если размер файла превышает 10 МБ, я начинаю получать ошибки.

Как я могу предотвратить эту ошибку?

Для чтения нормального файла мы используем код:

if ($handle) { while (($buffer = fgets($handle, 4096)) !== false) { $i1++; $content[$i1]=$buffer; } if (!feof($handle)) { echo "Error: unexpected fgets() fail\n"; } fclose($handle); } 

Мой файл может переместиться на 10 мб, но мне просто нужно прочитать последние несколько строк. Как мне это сделать?

благодаря

Solutions Collecting From Web of "Чтение больших файлов с конца"

Это не чистый PHP, но общим решением является использование команды tac, которая является возвратом cat и загружает файл в обратном порядке. Используйте exec () или passthru (), чтобы запустить его на сервере, а затем прочитать результаты. Пример использования:

 <?php $myfile = 'myfile.txt'; $command = "tac $myfile > /tmp/myfilereversed.txt"; exec($command); $currentRow = 0; $numRows = 20; // stops after this number of rows $handle = fopen("/tmp/myfilereversed.txt", "r"); while (!feof($handle) && $currentRow <= $numRows) { $currentRow++; $buffer = fgets($handle, 4096); echo $buffer."<br>"; } fclose($handle); ?> 

Вы можете использовать fopen и fseek для перемещения по файлу с обратной стороны. Например

 $fp = @fopen($file, "r"); $pos = -2; while (fgetc($fp) != "\n") { fseek($fp, $pos, SEEK_END); $pos = $pos - 1; } $lastline = fgets($fp); 

Это зависит от того, как вы интерпретируете «can».

Если вы задаетесь вопросом, можете ли вы сделать это напрямую (с помощью функции PHP), не читая все предыдущие строки, тогда ответ будет: Нет , вы не можете.

Окончание строки – это интерпретация данных, и вы можете знать только, где они находятся, если вы действительно читаете данные.

Если это действительно большой файл, я бы этого не сделал. Было бы лучше, если бы вы сканировали файл, начиная с конца, и постепенно читали блоки с конца до файла.

Обновить

Вот только PHP- метод для чтения последних n строк файла без прочтения всего:

 function last_lines($path, $line_count, $block_size = 512){ $lines = array(); // we will always have a fragment of a non-complete line // keep this in here till we have our next entire line. $leftover = ""; $fh = fopen($path, 'r'); // go to the end of the file fseek($fh, 0, SEEK_END); do{ // need to know whether we can actually go back // $block_size bytes $can_read = $block_size; if(ftell($fh) < $block_size){ $can_read = ftell($fh); } // go back as many bytes as we can // read them to $data and then move the file pointer // back to where we were. fseek($fh, -$can_read, SEEK_CUR); $data = fread($fh, $can_read); $data .= $leftover; fseek($fh, -$can_read, SEEK_CUR); // split lines by \n. Then reverse them, // now the last line is most likely not a complete // line which is why we do not directly add it, but // append it to the data read the next time. $split_data = array_reverse(explode("\n", $data)); $new_lines = array_slice($split_data, 0, -1); $lines = array_merge($lines, $new_lines); $leftover = $split_data[count($split_data) - 1]; } while(count($lines) < $line_count && ftell($fh) != 0); if(ftell($fh) == 0){ $lines[] = $leftover; } fclose($fh); // Usually, we will read too many lines, correct that here. return array_slice($lines, 0, $line_count); } 

Если ваш код не работает и сообщает об ошибке, вы должны включить ошибку в свои сообщения!

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

Самый эффективный способ решить проблему – это то, что предлагает Greenisha, и искать конец файла, а затем немного вернуться. Но маканизм Гриниши для возврата немного не очень эффективен.

Вместо этого рассмотрим метод получения последних нескольких строк из потока (т. Е. Где вы не можете искать):

 while (($buffer = fgets($handle, 4096)) !== false) { $i1++; $content[$i1]=$buffer; unset($content[$i1-$lines_to_keep]); } с while (($buffer = fgets($handle, 4096)) !== false) { $i1++; $content[$i1]=$buffer; unset($content[$i1-$lines_to_keep]); } 

Поэтому, если вы знаете, что максимальная длина линии равна 4096, вы должны:

 if (4096*lines_to_keep<filesize($input_file)) { fseek($fp, -4096*$lines_to_keep, SEEK_END); } 

Затем примените описанный выше цикл.

Поскольку C имеет более эффективные методы для работы с потоками байтов, самым быстрым решением (в системе POSIX / Unix / Linux / BSD) будет просто:

 $last_lines=system("last -" . $lines_to_keep . " filename"); 

Следующий фрагмент работал на меня.

$ file = popen ("tac $ filename", 'r');

while ($ line = fgets ($ file)) {

  echo $line; 

}

Ссылка: http://laughingmeme.org/2008/02/28/reading-a-file-backwards-in-php/

Вот еще одно решение. Он не имеет контроля длины строки в fgets (), вы можете добавить его.

 /* Read file from end line by line */ $fp = fopen( dirname(__FILE__) . '\\some_file.txt', 'r'); $lines_read = 0; $lines_to_read = 1000; fseek($fp, 0, SEEK_END); //goto EOF $eol_size = 2; // for windows is 2, rest is 1 $eol_char = "\r\n"; // mac=\r, unix=\n while ($lines_read < $lines_to_read) { if (ftell($fp)==0) break; //break on BOF (beginning...) do { fseek($fp, -1, SEEK_CUR); //seek 1 by 1 char from EOF $eol = fgetc($fp) . fgetc($fp); //search for EOL (remove 1 fgetc if needed) fseek($fp, -$eol_size, SEEK_CUR); //go back for EOL } while ($eol != $eol_char && ftell($fp)>0 ); //check EOL and BOF $position = ftell($fp); //save current position if ($position != 0) fseek($fp, $eol_size, SEEK_CUR); //move for EOL echo fgets($fp); //read LINE or do whatever is needed fseek($fp, $position, SEEK_SET); //set current position $lines_read++; } fclose($fp); 

Для Linux вы можете сделать

 $linesToRead = 10; exec("tail -n{$linesToRead} {$myFileName}" , $content); 

Вы получите массив строк в переменной $ content

Чистое PHP-решение

 $f = fopen($myFileName, 'r'); $maxLineLength = 1000; // Real maximum length of your records $linesToRead = 10; fseek($f, -$maxLineLength*$linesToRead, SEEK_END); // Moves cursor back from the end of file $res = array(); while (($buffer = fgets($f, $maxLineLength)) !== false) { $res[] = $buffer; } $content = array_slice($res, -$linesToRead); 

Хорошо, ища то же самое, я могу через следующее и подумал, что это может быть полезно и другим людям, поэтому поделитесь им здесь:

/ * Чтение файла с конца строки за строкой * /

 function tail_custom($filepath, $lines = 1, $adaptive = true) { // Open file $f = @fopen($filepath, "rb"); if ($f === false) return false; // Sets buffer size, according to the number of lines to retrieve. // This gives a performance boost when reading a few lines from the file. 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); } 

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

Мне нужны последние 15 строк из очень большого файла журнала, и в целом их было около 3000 символов. Поэтому я просто хватаю последние 8000 байт, чтобы быть в безопасности, а затем прочитайте файл как обычно и возьмите то, что мне нужно с самого конца.

  $fh = fopen($file, "r"); fseek($fh, -8192, SEEK_END); $lines = array(); while($lines[] = fgets($fh)) {} 

Это, возможно, даже более эффективно, чем самый высокий рейтинг ответа, который читает символ файла по символу, сравнивает каждый символ и разбивается на основе символов новой строки.

Как сказал Эйнштейн, каждая вещь должна быть сделана максимально простой, но не простой. На этом этапе вам нужна структура данных, структура данных LIFO или просто поместите стек.