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 相关文章推荐
php miniBB中文乱码问题解决方法
Nov 25 PHP
PHP strtok()函数的优点分析
Mar 02 PHP
ajax实现无刷新分页(php)
Jul 18 PHP
rrmdir php中递归删除目录及目录下的文件
May 15 PHP
PHP 获取远程文件大小的3种解决方法
Jul 11 PHP
thinkphp实现图片上传功能分享
Mar 04 PHP
php+html5基于websocket实现聊天室的方法
Jul 17 PHP
php数组函数array_key_exists()小结
Dec 10 PHP
PHP实现的注册,登录及查询用户资料功能API接口示例
Jun 06 PHP
Mac系统完美安装PHP7详细教程
Jun 06 PHP
THINKPHP5分页数据对象处理过程解析
Oct 28 PHP
一文搞懂php的垃圾回收机制
Jun 18 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
PHP读MYSQL中文乱码的解决方法
2006/12/17 PHP
Win下如何安装PHP的APC拓展
2013/08/07 PHP
PHP实现支持GET,POST,Multipart/form-data的HTTP请求类
2014/09/24 PHP
CodeIgniter使用smtp服务发送html邮件的方法
2015/06/10 PHP
PHP超低内存遍历目录文件和读取超大文件的方法
2019/05/01 PHP
js 学习笔记(三)
2009/12/29 Javascript
HTML颜色选择器实现代码
2010/11/23 Javascript
js 获取后台的字段 改变 checkbox的被选中的状态 代码
2013/06/05 Javascript
js获取电脑分辨率的思路及操作
2013/11/22 Javascript
js 显示base64编码的二进制流网页图片
2014/04/04 Javascript
jQuery获取标签文本内容和html内容的方法
2015/03/27 Javascript
深入浅析JavaScript中的作用域和上下文
2016/03/26 Javascript
JavaScript 身份证号有效验证详解及实例代码
2016/10/20 Javascript
TypeScript学习之强制类型的转换
2016/12/27 Javascript
JS module的导出和导入的实现代码
2019/02/25 Javascript
Element Rate 评分的使用方法
2020/07/27 Javascript
[02:53]DOTA2英雄基础教程 山岭巨人小小
2013/12/09 DOTA
Python自动化测试工具Splinter简介和使用实例
2014/05/13 Python
Python中使用items()方法返回字典元素对的教程
2015/05/21 Python
python 写的一个爬虫程序源码
2016/02/28 Python
python日志记录模块实例及改进
2017/02/12 Python
浅谈使用Python内置函数getattr实现分发模式
2018/01/22 Python
python实现识别手写数字 python图像识别算法
2020/03/23 Python
Python 找到列表中满足某些条件的元素方法
2018/06/26 Python
python实现小球弹跳效果
2019/05/10 Python
一篇文章了解Python中常见的序列化操作
2019/06/20 Python
PyQt5响应回车事件的方法
2019/06/25 Python
kafka监控获取指定topic的消息总量示例
2019/12/23 Python
python装饰器相当于函数的调用方式
2019/12/27 Python
Python TestSuite生成测试报告过程解析
2020/07/23 Python
Python爬虫爬取有道实现翻译功能
2020/11/27 Python
前端canvas动画如何转成mp4视频的方法
2019/06/17 HTML / CSS
Madda Fella官网:美国冒险家服装品牌
2020/01/16 全球购物
出租房屋协议书
2014/09/14 职场文书
纪念一二九运动演讲稿
2014/09/16 职场文书
五年级作文之学校的四季
2019/12/05 职场文书