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 相关文章推荐
用IE远程创建Mysql数据库的简易程序
Oct 09 PHP
PHP基础知识回顾
Aug 16 PHP
探讨PHP函数ip2long转换IP时数值太大产生负数的解决方法
Jun 06 PHP
win7下memCache的安装过程(具体操作步骤)
Jun 28 PHP
IIS下PHP的三种配置方式对比
Nov 20 PHP
网站防止被刷票的一些思路与方法
Jan 08 PHP
通过php修改xml文档内容的方法
Jan 23 PHP
PHP获取指定时间段之间的 年,月,天,时,分,秒
Jun 05 PHP
PHP入门教程之自定义函数用法详解(创建,调用,变量,参数,返回值等)
Sep 11 PHP
yii2.0整合阿里云oss的示例代码
Sep 19 PHP
PHP explode()函数用法讲解
Feb 15 PHP
php实现的生成排列算法示例
Jul 25 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
如何开始收听短波广播
2021/03/01 无线电
PHP开发文件系统实例讲解
2006/10/09 PHP
PHP stream_context_create()作用和用法分析
2011/03/29 PHP
php inc文件使用的风险和注意事项
2013/11/12 PHP
Thinkphp5.0 框架的请求方式与响应方式分析
2019/10/14 PHP
Extjs学习笔记之五 一个小细节renderTo和applyTo的区别
2010/01/07 Javascript
浏览器解析js生成的html出现样式问题的解决方法
2012/04/16 Javascript
在javascript中对于DOM的加强
2013/04/11 Javascript
JavaScript 上万关键字瞬间匹配实现代码
2013/07/07 Javascript
js控制浏览器全屏示例代码
2014/02/20 Javascript
AngularJS用户选择器指令实例分析
2016/11/04 Javascript
浅谈jQuery中Ajax事件beforesend及各参数含义
2016/12/03 Javascript
node使用Koa2搭建web项目的方法
2017/10/17 Javascript
微信小程序表单验证功能完整实例
2017/12/01 Javascript
js判断传入时间和当前时间大小实例(超简单)
2018/01/11 Javascript
JavaScript设计模式之构造函数模式实例教程
2018/07/02 Javascript
详解Angular6学习笔记之主从组件
2018/09/05 Javascript
解决echarts中横坐标值显示不全(自动隐藏)问题
2020/07/20 Javascript
JS禁用右键、禁用Ctrl+u、禁用Ctrl+s、禁用F12的实现代码
2020/12/01 Javascript
详解Python中find()方法的使用
2015/05/18 Python
python使用wxpython开发简单记事本的方法
2015/05/20 Python
如何在sae中设置django,让sae的工作环境跟本地python环境一致
2017/11/21 Python
django rest framework 自定义返回方式
2020/07/12 Python
python怎么删除缓存文件
2020/07/19 Python
html5使用canvas绘制一张图片
2014/12/15 HTML / CSS
阿迪达斯俄罗斯官方商城:adidas俄罗斯
2017/03/08 全球购物
什么是Smarty变量操作符?如何使用Smarty变量操作符
2014/07/18 面试题
大四毕业生学习总结的自我评价
2013/10/31 职场文书
十佳美德少年事迹材料
2014/02/05 职场文书
化工工艺设计求职信
2014/06/25 职场文书
民政局个人整改措施
2014/09/24 职场文书
关于运动会的广播稿50字
2014/10/17 职场文书
教师党的群众路线教育实践活动学习心得体会
2014/10/30 职场文书
2015年底工作总结范文
2015/05/15 职场文书
2019中小学生安全过暑期倡议书
2019/06/24 职场文书
windows安装python超详细图文教程
2021/05/21 Python