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 相关文章推荐
关于Appserv无法打开localhost问题的解决方法
Oct 16 PHP
php实现单链表的实例代码
Mar 22 PHP
基于在生产环境中使用php性能测试工具xhprof的详解
Jun 03 PHP
163的邮件用phpmailer发送(实例详解)
Jun 24 PHP
PHP的反射类ReflectionClass、ReflectionMethod使用实例
Aug 05 PHP
使用PHPMailer实现邮件发送代码分享
Oct 23 PHP
php使用Cookie实现和用户会话的方法
Jan 21 PHP
php遍历替换目录下文件指定内容的方法
Nov 10 PHP
CodeIgniter框架常见用法工作总结
Mar 16 PHP
php使用crypt()函数进行加密
Jun 08 PHP
PDO::prepare讲解
Jan 29 PHP
Laravel+Intervention实现上传图片功能示例
Jul 09 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第一季视频教程(李炎恢+php100 不断更新)
2011/05/29 PHP
PHP中将一个字符串部分字符用星号*替代隐藏的实现代码
2019/09/08 PHP
thinkphp框架无限级栏目的排序功能实现方法示例
2020/03/29 PHP
PHP网页缓存技术优点及代码实例
2020/07/29 PHP
Javascript里使用Dom操作Xml
2006/09/20 Javascript
jquery复选框CHECKBOX全选、反选
2008/08/30 Javascript
javascript 混合的构造函数和原型方式,动态原型方式
2009/12/07 Javascript
改善你的jQuery的25个步骤 千倍级效率提升
2010/02/11 Javascript
Javascript中的变量使用说明
2010/05/18 Javascript
jquery和javascript中如何将一元素的内容赋给另一元素
2014/01/09 Javascript
Jquery动态添加输入框的方法
2015/05/29 Javascript
jQuery代码实现表格中点击相应行变色功能
2016/05/09 Javascript
深入浅析JS的数组遍历方法(推荐)
2016/06/15 Javascript
Boostrap基础教程之JavaScript插件篇
2016/09/08 Javascript
Node.js查找当前目录下文件夹实例代码
2017/03/07 Javascript
详解Vue-cli代理解决跨域问题
2017/09/27 Javascript
nodejs实现解析xml字符串为对象的方法示例
2018/03/14 NodeJs
JS与jQuery实现ListBox上移,下移,左移,右移操作功能示例
2018/05/31 jQuery
详解解决使用axios发送json后台接收不到的问题
2018/06/27 Javascript
浅谈Vue.use的使用
2018/08/29 Javascript
angular学习之动态创建表单的方法
2018/12/07 Javascript
[06:13]DOTA2进化论(修改版)
2013/10/08 DOTA
python计算方程式根的方法
2015/05/07 Python
python制作爬虫爬取京东商品评论教程
2016/12/16 Python
win7上python2.7连接mysql数据库的方法
2017/01/14 Python
对numpy的array和python中自带的list之间相互转化详解
2018/04/13 Python
python调用OpenCV实现人脸识别功能
2018/05/25 Python
深入浅析Python的类
2018/06/22 Python
django在保存图像的同时压缩图像示例代码详解
2020/02/11 Python
python实现udp传输图片功能
2020/03/20 Python
matplotlib设置颜色、标记、线条,让你的图像更加丰富(推荐)
2020/09/25 Python
欧洲最古老的鞋厂:Peter Kaiser
2019/11/05 全球购物
解释一下ArrayList Vector和LinkedList的实现和区别
2013/04/26 面试题
北京鼎普科技股份有限公司软件测试面试题
2012/04/07 面试题
入团者的自我评价分享
2013/12/02 职场文书
物流创业计划书
2014/02/01 职场文书