读取大文件一直是一个头痛的问题,我们像利用php开拓读取小文件可以直接利用各类函数实现,但一到大文章就会发明常用的要领是无法正常利用或时间太长太卡了,下面我们就一起来看看关于php读取大文件问题办理步伐,但愿例子能辅佐到列位。
在PHP中,对付文件的读取时,最快捷的方法莫过于利用一些诸如file、file_get_contents之类的函数,简简朴单的几行代码就能 很大度的完成我们所需要的成果。但当所操纵的文件是一个较量大的文件时,这些函数大概就显的力有未逮, 下面将从一个需求入手来说明对付读取大文件时,常用的操纵要领。
需求:
有一个800M的日志文件,约莫有500多万行, 用PHP返回最后几行的内容。
实现要领:
1. 直接回收file函数来操纵由于 file函数是一次性将所有内容读入内存,而PHP为了防备一些写的较量糟糕的措施占用太多的内存而导致系统内存不敷,使处事器呈现宕机,所以默认环境下限制只能最大利用内存16M,这是通过php.ini里的 memory_limit = 16M 来举办配置,这个值假如配置-1,则内存利用量不受限制。
下面是一段用file来取出这具文件最后一行的代码:
<?php ini_set('memory_limit', '-1'); $file = 'access.log'; $data = file($file); $line = $data[count($data) - 1]; echo $line; ?>整个代码执行完成耗时 116.9613 (s)。
我呆板是2个G的内存,当按下F5运行时,系统直接变灰,差不多20分钟后才规复过来,可见将这么大的文件全部直接读入内存,效果是几多严重,所以不在万 不得以,memory_limit这对象不能调得太高,不然只有打电话给机房,让reset呆板了。
2.直接挪用Linux的 tail 呼吁来显示最 后几行在Linux呼吁行下,可以直接利用 tail -n 10 access.log 很等闲的显示日志文件最后几行,可以直接用PHP来挪用tail呼吁,执行PHP代码如下:
<?php $file = 'access.log'; $file = escapeshellarg($file); // 对呼吁行参数举办安详转义 $line = `tail -n 1 $file`; echo $line; ?>整个代码执行完成耗时 0.0034 (s)
3. 直接利用PHP的 fseek 来举办文件操纵这种方法是最为普遍的方法,它不需要将文件的内容全部读入内容,而是直接通过指针来操纵,所以效率是相当高效的。在利用fseek来对文件举办操纵时,也有多种差异的要领,效率大概也是略有不同的,下面是常用的两种要领:
要领一首先通过fseek找到文件的最后一位EOF,然后找最后一行的起始位置,取这一行的数据,再找次一行的起始位置, 再取这一行的位置,依次类推,直到找到了$num行。
实现代码如下
<?php $fp = fopen($file, "r"); $line = 10; $pos = -2; $t = " "; $data = ""; while ($line > 0) { while ($t != "\n") { fseek($fp, $pos, SEEK_END); $t = fgetc($fp); $pos--; } $t = " "; $data .= fgets($fp); $line--; } fclose($fp); echo $data ?>整个代码执行完成耗时 0.0095 (s)
要领二照旧回收fseek的方法从文件最后开始读,但这时不是一位一位的读,而是一块一块的读,每读一块数据时,就将读取后的数据放在一个buf里,然后通过换 行符(\n)的个数来判定是否已经读完最后$num行数据。
实现代码如下
<?php $fp = fopen($file, "r"); $num = 10; $chunk = 4096; $fs = sprintf("%u", filesize($file)); $max = (intval($fs) == PHP_INT_MAX) ? PHP_INT_MAX : filesize($file); for ($len = 0; $len < $max; $len += $chunk) { $seekSize = ($max - $len > $chunk) ? $chunk : $max - $len; fseek($fp, ($len + $seekSize) * -1, SEEK_END); $readData = fread($fp, $seekSize) . $readData; if (substr_count($readData, "\n") >= $num + 1) { preg_match("!(.*?\n){" . ($num) . "}$!", $readData, $match); $data = $match[0]; break; } } fclose($fp); echo $data; ?>整个代码执行完成耗时 0.0009(s)。
要领三<?php function tail($fp, $n, $base = 5) { assert($n > 0); $pos = $n + 1; $lines = array(); while (count($lines) <= $n) { try { fseek($fp, -$pos, SEEK_END); } catch (Exception $e) { fseek(0); break; } $pos *= $base; while (!feof($fp)) { array_unshift($lines, fgets($fp)); } } return array_slice($lines, 0, $n); } var_dump(tail(fopen("access.log", "r+"), 10)); ?>整个代码执行完成耗时 0.0003(s)
要领四