当前位置:首页 > 技术文章 > php > php读取大文件提供性能的方法
php读取大文件提供性能的方法
文章来源:本站原创  浏览次数:805  发布日期:2013-05-10

问题描述:一个文件有几十M,几百M,甚至上G的大小,用PHP去读取是不是很痛苦的事情。常常会出现内存不足的报错。PHP有没有更好的办法去解决这个问题呢?

一般的程序去读文件的内容最常用的可能就是file file_get_contents 这种方法了,这种方法在文件不大,内存充足的情况下,确实是没有问题的。

当时如果文件一大,要么报错,要么程序卡死。

起初我也是用的这个方法,结果可想而知了。

经过一方折腾之后,我找到了很好的办法解决这个问题了。

下面请看函数:


/* 返回文件从X行到Y行的内容(支持php5、php4) */
public function getFileLines($filename, $startLine = 1, $endLine=50, $method='rb') {
    $content = array();
    $count = $endLine - $startLine;
    if(version_compare(PHP_VERSION, '5.1.0', '>=')){/* 判断php版本(因为要用到SplFileObject,PHP>=5.1.0) */
        $fp = new SplFileObject($filename, $method);
        $fp->seek($startLine-1);/* 转到第N行, seek方法参数从0开始计数 */
        for($i = 0; $i <= $count; ++$i) {
            $content[] = unserialize($fp->current());/* current()获取当前行内容 */
            $fp->next();/* 下一行 */
        }
    }else{/*PHP<5.1 */
        $fp = fopen($filename, $method);
        if(!$fp) return 'error:can not read file';
        for ($i=1;$i<$startLine;++$i) {/* 跳过前$startLine行 */
            fgets($fp);
        }
        for($i;$i<=$endLine;++$i){
            $content[] = unserialize(fgets($fp));/* 读取文件行内容 */
        }
        fclose($fp);
    }
    return array_filter($content); /* array_filter过滤:false,null,'' */
}

这个只是从文件中从X行取到Y行的行数,注意这里的换行符需要是"\r\n",不然取出来的数据就不准了。

一个文件如果知道有几行的话,就可以控制获取一定的行数的数据,然后放入数据库。这样不管的读取大文件的性能,还是写入数据库的性能,都能得到很大的提高了。

下面是获取文件的行数的方法

$temp_file = 'error.log';
$fp = fopen($temp_file ,'r') or die("open file failure!");
$total_line = 0;
if($fp){
    /* 获取文件的一行内容,注意:需要php5才支持该函数; */
    while(stream_get_line($fp, 8192, "\r\n")){
        $total_line++;
    }
    fclose($fp);
}

接下来好操作了吧?

以下的程序主要是每次最大入库1000条,余数不足1000的就入余数。

入库10W条数据时间也才几秒,所以说性能是大大滴的好的。

define('EACH_NUM', 1000);/* 每次入库的条数 */
if(!$total_line) die('no record!');
$logs = mod('logs_error');
$temp = array();
$num = ceil($total_line/EACH_NUM);
$mod = fmod($total_line,EACH_NUM);
for($i=0;$i<$num;$i++){
    if(($i+1) == $num && $mod){
        $temp = $logs->getFileLines($temp_file, $i*EACH_NUM+1, $mod);
        $insert_num += $mod;
    }else{
        $temp = $logs->getFileLines($temp_file, $i*EACH_NUM+1, ($i+1)*EACH_NUM);
        $insert_num += EACH_NUM;
    }
    /* 入库 */
    $logs->insert($temp);
}
@unlink($temp_file);
echo "Insert Record:{$insert_num} \nSuccess";
exit();

如果你还有更好的操作文件的方法,或者是更好的入库的方法,可以联系我,我们交流下。


原文来自:php读取大文件提供性能的方法 http://www.redyun.net/technology/101.html

红云案例Case