php处理大的日志文件

来源:互联网 发布:手机淘宝宝贝排名查询 编辑:程序博客网 时间:2024/04/20 13:47

php为了防止内存占用过多,在php.ini限制了内存占用,memory_limit = 16M默认为16M,可

以修改脚本占用内存限制,比如为-1,无限制。

做了如下实验。

 

场景:

一个1G左右的日志文件,大约700万行。

方案:

一、file函数直读。

代码如下

ini_set('memory_limit','-1');

$file = 'access.log';

$data = file($file);

$line = $data[count($data)-1];

echo $line;

机器直接无响应。。大概运行了200多秒。。

二、调用linux的tail函数

在linux命令行下,可以直接使用tail -n 10 access.log很轻易的显示日志文件某行。

file = 'access.log';

$file = escapeshellarg($file); // 对命令行参数进行安全转义

$line = `tail -n 1 $file`;

echo $line;

时间:0.0045秒,已经达到可用标准,但对环境有要求。

 三、fseek函数

fseek函数不需要把文件全部装入内存,而是直接通过指针来操作,所以效率很高。代码:

$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.0105秒

再提升一点,按块读取,然后计算块内的\n标记来算到了多少行。

$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 &gt; $chunk) ? $chunk : $max - $len;

    fseek($fp, ($len + $seekSize) * -1, SEEK_END);

    $readData = fread($fp, $seekSize) . $readData;

 

    if (substr_count($readData, "\n") &gt;= $num + 1) {

        preg_match("!(.*?\n){".($num)."}$!", $readData, $match);

        $data = $match[0];

        break;

    }

}

fclose($fp);

echo $data;

 时间:0.002秒

 再快一点的话,可以判断如果行数大于一半,可以从后往前取,这样二分之后,取后面的速度会

更加快速。

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)); 

 实际应用中再根据具体情况调整。


原创粉丝点击