php对大文件进行读取操作的实现代码


Posted in PHP onJanuary 23, 2013

在php中,对于文件的读取时,最快捷的方式莫过于使用一些诸如file、file_get_contents之类的函数,简简单单的几行代码就能很漂亮的完成我们所需要的功能。但当所操作的文件是一个比较大的文件时,这些函数可能就显的力不从心, 下面将从一个需求入手来说明对于读取大文件时,常用的操作方法。
需求

有一个800M的日志文件,大约有500多万行, 用php返回最后几行的内容。

实现方法

1. 直接采用file函数来操作

注:由于 file函数是一次性将所有内容读入内存,而php为了防止一些写的比较糟糕的程序占用太多的内存而导致系统内存不足,使服务器出现宕机,所以默认情况下限制只能最大使用内存16M,这是通过php.ini里的memory_limit = 16M来进行设置,这个值如果设置-1,则内存使用量不受限制.

下面是一段用file来取出这具文件最后一行的代码.
整个代码执行完成耗时 116.9613 (s).

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

我机器是2个G的内存,当按下F5运行时,系统直接变灰,差不多20分钟后才恢复过来,可见将这么大的文件全部直接读入内存,后果是多少严重,所以不在万不得以,memory_limit这东西不能调得太高,否则只有打电话给机房,让reset机器了.

2.直接调用linux的tail命令来显示最后几行

在linux命令行下,可以直接使用tail -n 10 access.log很轻易的显示日志文件最后几行,可以直接用php来调用tail命令,执行php代码如下.
整个代码执行完成耗时 0.0034 (s)

file = 'access.log'; 
$file = escapeshellarg($file); // 对命令行参数进行安全转义 
$line = `tail -n 1 $file`; 
echo $line;

3. 直接使用php的fseek来进行文件操作

这种方式是最为普遍的方式,它不需要将文件的内容全部读入内容,而是直接通过指针来操作,所以效率是相当高效的.在使用fseek来对文件进行操作时,也有多种不同的方法,效率可能也是略有差别的,下面是常用的两种方法.

方法一
首先通过fseek找到文件的最后一位EOF,然后找最后一行的起始位置,取这一行的数据,再找次一行的起始位置,再取这一行的位置,依次类推,直到找到了$num行。
实现代码如下
整个代码执行完成耗时 0.0095 (s)

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

方法二
还是采用fseek的方式从文件最后开始读,但这时不是一位一位的读,而是一块一块的读,每读一块数据时,就将读取后的数据放在一个buf里,然后通过换行符(\n)的个数来判断是否已经读完最后$num行数据.
实现代码如下
整个代码执行完成耗时 0.0009(s).
$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.0003(s)
ini_set('memory_limit','-1'); 
$file = 'access.log'; 
$data = file($file); 
$line = $data[count($data)-1]; 
echo $line;
PHP 相关文章推荐
phpfans留言版用到的数据操作类和分页类
Jan 04 PHP
PHP 检查扩展库或函数是否可用的代码
Apr 06 PHP
备份mysql数据库的php代码(一个表一个文件)
May 28 PHP
ThinkPHP的L方法使用简介
Jun 18 PHP
全面解读PHP的Yii框架中的日志功能
Mar 17 PHP
PHP判断FORM表单或URL参数来的数据是否为整数的方法
Mar 25 PHP
thinkPHP使用pclzip打包备份mysql数据库的方法
Apr 30 PHP
PHP随机数 C扩展随机数
May 04 PHP
smarty循环嵌套用法示例分析
Jul 19 PHP
php微信公众平台示例代码分析(二)
Dec 06 PHP
CI框架(CodeIgniter)实现的导入、导出数据操作示例
May 24 PHP
解决laravel 出现ajax请求419(unknown status)的问题
Sep 03 PHP
php删除与复制文件夹及其文件夹下所有文件的实现代码
Jan 23 #PHP
php删除文件夹及其文件夹下所有文件的函数代码
Jan 23 #PHP
php定时删除文件夹下文件(清理缓存文件)
Jan 23 #PHP
PHP关联数组的10个操作技巧
Jan 21 #PHP
用PHP即时捕捉PHP中的错误并发送email通知的实现代码
Jan 19 #PHP
PHP中CURL方法curl_setopt()函数的参数分享
Jan 19 #PHP
php牛逼的面试题分享
Jan 18 #PHP
You might like
【动漫杂谈】关于《请在T台上微笑》
2020/03/03 日漫
全国FM电台频率大全 - 11 浙江省
2020/03/11 无线电
php实现XSS安全过滤的方法
2015/07/29 PHP
Yii中的cookie的发送和读取
2016/07/27 PHP
php实现将HTML页面转换成word并且保存的方法
2016/10/14 PHP
PHP 7安装调试工具Xdebug扩展的方法教程
2017/06/17 PHP
Prototype源码浅析 String部分(四)之补充
2012/01/16 Javascript
extjs ColumnChart设置不同的颜色实现代码
2013/05/17 Javascript
jQuery之字体大小的设置方法
2014/02/27 Javascript
javascript对中文按照拼音排序代码
2014/08/20 Javascript
jQuery动画与特效详解
2015/02/01 Javascript
EasyUi combotree 实现动态加载树节点
2016/04/01 Javascript
整理一下常见的IE错误
2016/11/18 Javascript
nodejs前端自动化构建环境的搭建
2017/07/26 NodeJs
vue 之 .sync 修饰符示例详解
2018/04/21 Javascript
vue-cli3 项目从搭建优化到docker部署的方法
2019/01/28 Javascript
QML实现圆环颜色选择器
2019/09/25 Javascript
element的el-table中记录滚动条位置的示例代码
2019/11/06 Javascript
微信小程序实现滚动加载更多的代码
2019/12/06 Javascript
[03:40]2014DOTA2国际邀请赛 B神专访:躲箭真的很难
2014/07/13 DOTA
[01:54]胎教DOTA2 准妈妈玩家现身中国区预选赛
2016/06/26 DOTA
在Python中处理字符串之ljust()方法的使用简介
2015/05/19 Python
Python计算已经过去多少个周末的方法
2015/07/25 Python
Python实现处理逆波兰表达式示例
2018/07/30 Python
python实现自动获取IP并发送到邮箱
2018/12/26 Python
深入了解如何基于Python读写Kafka
2019/12/31 Python
python实现拼接图片
2020/03/23 Python
美国时装品牌:Nautica(诺帝卡)
2016/08/28 全球购物
水芝澳美国官网:H2O Plus
2016/10/15 全球购物
意大利简约的休闲品牌:Aspesi
2018/02/08 全球购物
购买正版游戏和游戏激活码:Green Man Gaming
2019/11/06 全球购物
电子商务专业个人的自我评价
2013/11/19 职场文书
乡镇党建工作汇报材料
2014/08/14 职场文书
试用期自我评价范文
2015/03/10 职场文书
销售会议开幕词
2016/03/04 职场文书
7个你应该知道的JS原生错误类型
2021/04/29 Javascript