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脚本的10个技巧(4)
Oct 09 PHP
php md5下16位和32位的实现代码
Apr 09 PHP
php 将bmp图片转为jpg等其他任意格式的图片
Jun 21 PHP
php 不使用js实现页面跳转
Feb 11 PHP
PHP集成百度Ueditor 1.4.3
Nov 23 PHP
PHP查询快递信息的方法
Mar 07 PHP
使用PHP+AJAX让WordPress动态加载文章的教程
Dec 11 PHP
PHP实现多图上传和单图上传功能
May 17 PHP
php微信开发之谷歌测距
Jun 14 PHP
PHP中十六进制颜色与RGB颜色值互转的方法
Mar 18 PHP
php操作redis数据库常见方法实例总结
Feb 20 PHP
基于php解决json_encode中文UNICODE转码问题
Nov 10 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写出自己的BLOG系统 2
2010/04/12 PHP
php 随机排序广告的实现代码
2011/05/09 PHP
PHP实现上传文件并存进数据库的方法
2015/07/16 PHP
PHP实现断点续传乱序合并文件的方法
2018/09/06 PHP
php封装实现钉钉机器人报警接口的示例代码
2020/08/08 PHP
让回调函数 showResponse 也带上参数的代码
2007/08/13 Javascript
《JavaScript高级程序设计》阅读笔记(二) ECMAScript中的原始类型
2012/02/27 Javascript
通过JS自动隐藏手机浏览器的地址栏实现原理与代码
2013/01/02 Javascript
深入理解Javascript动态方法调用与参数修改的问题
2013/12/10 Javascript
javascript向后台传送相同属性的参数即数组参数
2014/02/17 Javascript
JS实现无限级网页折叠菜单(类似树形菜单)效果代码
2015/09/17 Javascript
Bootstrap Paginator分页插件与ajax相结合实现动态无刷新分页效果
2016/05/27 Javascript
Angular表单验证实例详解
2016/10/20 Javascript
jquery实现弹窗功能(窗口居中显示)
2017/02/27 Javascript
浅析vue给不同环境配置不同打包命令
2018/08/17 Javascript
vue防止花括号{{}}闪烁v-text和v-html、v-cloak用法示例
2019/03/13 Javascript
[01:15:45]DOTA2上海特级锦标赛B组小组赛#1 Alliance VS Spirit第一局
2016/02/26 DOTA
用python 制作图片转pdf工具
2015/01/30 Python
深入探究Python中变量的拷贝和作用域问题
2015/05/05 Python
Python+Selenium使用Page Object实现页面自动化测试
2019/07/14 Python
python实现切割url得到域名、协议、主机名等各个字段的例子
2019/07/25 Python
Python函数的默认参数设计示例详解
2019/12/01 Python
pytorch中tensor.expand()和tensor.expand_as()函数详解
2019/12/27 Python
keras用auc做metrics以及早停实例
2020/07/02 Python
python中_del_还原数据的方法
2020/12/09 Python
巧用 CSS3的webkit-box-reflect 倒影实现各类动效
2021/03/05 HTML / CSS
详解Html5中video标签那些属性和方法
2019/07/01 HTML / CSS
Html5之title吸顶功能
2018/06/04 HTML / CSS
翻新二手苹果产品的网络领导者:Mac of all Trades
2017/12/19 全球购物
UDP协议功能
2013/01/06 面试题
工程现场管理求职自荐信
2013/10/02 职场文书
初三物理教学反思
2014/01/21 职场文书
大学毕业自我评价
2014/02/02 职场文书
中学生期末评语
2014/02/03 职场文书
广告创意求职信
2014/03/17 职场文书
贸易经济专业自荐书
2014/06/29 职场文书