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下载文件源代码(强制任意文件格式下载)
May 09 PHP
ThinkPHP框架实现session跨域问题的解决方法
Jul 01 PHP
php合并数组中相同元素的方法
Nov 13 PHP
php中动态调用函数的方法
Mar 16 PHP
php实现的网络相册图片防盗链完美破解方法
Jul 01 PHP
详解PHP原生DOM对象操作XML的方法
Oct 17 PHP
PHP实现图片批量打包下载功能
Mar 01 PHP
老生常谈php 正则中的i,m,s,x,e分别表示什么
Mar 02 PHP
thinkphp5 URL和路由的功能详解与实例
Dec 26 PHP
PHP+Ajax实现上传文件进度条动态显示进度功能
Jun 04 PHP
PHP基于DateTime类解决Unix时间戳与日期互转问题【针对1970年前及2038年后时间戳】
Jun 13 PHP
浅析PHP中json_encode与json_decode的区别
Jul 15 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
PHP7标量类型declare用法实例分析
2016/09/26 PHP
PHP检测接口Traversable用法详解
2017/12/29 PHP
收集的网上用的ajax之chat.js文件
2007/04/08 Javascript
JQuery动态给table添加、删除行 改进版
2011/01/19 Javascript
jQuery+CSS实现菜单滑动伸展收缩(仿淘宝)
2013/03/22 Javascript
关于js中for in的缺陷浅析
2013/12/02 Javascript
js日期、星座的级联显示代码
2014/01/23 Javascript
jquery实现通用的内容渐显Tab选项卡效果
2015/09/07 Javascript
AngularJS基础 ng-mousemove 指令简单示例
2016/08/02 Javascript
微信小程序 绘图之饼图实现
2016/10/24 Javascript
用iframe实现不刷新整个页面上传图片的实例
2016/11/18 Javascript
jquery中绑定事件的异同
2017/02/28 Javascript
JS实现线性表的链式表示方法示例【经典数据结构】
2017/04/11 Javascript
jQuery简单实现对数组去重及排序操作实例
2017/10/31 jQuery
基于datepicker定义自己的angular时间组件的示例
2018/03/14 Javascript
jquery ajax加载数据前台渲染方式 不用for遍历的方法
2018/08/09 jQuery
JS实现从对象获取对象中单个键值的方法示例
2019/06/05 Javascript
javascript中this的用法实践分析
2019/07/29 Javascript
JS造成内存泄漏的几种情况实例分析
2020/03/02 Javascript
[02:30]DOTA2放量测试专访海涛:呼吁保护新手玩家
2013/08/26 DOTA
[02:33]DOTA2英雄基础教程 司夜刺客
2013/12/04 DOTA
[00:12]DAC2018 天才少年转战三号位,他的SOLO是否仍如昔日般强大?
2018/04/06 DOTA
[51:43]OG vs LGD 2018国际邀请赛淘汰赛BO3 第五场 8.26
2018/08/30 DOTA
Python 初始化多维数组代码
2008/09/06 Python
python按照多个字符对字符串进行分割的方法
2015/03/17 Python
Python中import导入上一级目录模块及循环import问题的解决
2016/06/04 Python
Python提取频域特征知识点浅析
2019/03/04 Python
Flask中endpoint的理解(小结)
2019/12/11 Python
pandas中的数据去重处理的实现方法
2020/02/10 Python
JD Sports瑞典:英国领先的运动时尚商店
2018/01/28 全球购物
香港士多网上超级市场:Ztore
2021/01/09 全球购物
瀑布模型都有哪些优缺点
2014/06/23 面试题
综合办公室主任职责
2013/12/16 职场文书
化学教学随笔感言
2014/02/19 职场文书
预备党员转正考核材料
2014/06/03 职场文书
环境科学专业求职信
2014/08/04 职场文书