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&amp;mysql(一)
Oct 09 PHP
PHP语法速查表
Dec 06 PHP
PHP常用函数小技巧
Sep 11 PHP
php代码收集表单内容并写入文件的代码
Jan 29 PHP
Eclipse中php插件安装及Xdebug配置的使用详解
Apr 25 PHP
linux环境apache多端口配置虚拟主机的方法深入介绍
Jun 09 PHP
php开启与关闭错误提示适用于没有修改php.ini的权限
Oct 16 PHP
UTF-8正则表达式如何匹配汉字
Aug 03 PHP
zen cart实现订单中增加paypal中预留电话的方法
Jul 12 PHP
php结合redis高并发下发帖、发微博的实现方法
Dec 15 PHP
Laravel基础-关于引入公共文件的两种方式
Oct 18 PHP
PHP pthreads v3下worker和pool的使用方法示例
Feb 21 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
mysql 性能的检查和优化方法
2009/06/21 PHP
CI使用Tank Auth转移数据库导致密码用户错误的解决办法
2014/06/12 PHP
PHP+MySQL修改记录的方法
2015/01/21 PHP
php实现SAE上使用storage上传与下载文件的方法
2015/06/29 PHP
Yii2搭建后台并实现rbac权限控制完整实例教程
2016/04/28 PHP
微信支付开发维权通知实例
2016/07/12 PHP
PHP实现登录搜狐广告获取广告联盟数据的方法【附demo源码】
2016/10/14 PHP
thinkPHP线上自动加载异常与修复方法实例分析
2016/12/01 PHP
thinkphp3.2实现在线留言提交验证码功能
2017/07/19 PHP
PHP实现的ID混淆算法类与用法示例
2018/08/10 PHP
php设计模式之模板模式实例分析【星际争霸游戏案例】
2020/03/24 PHP
浅谈JavaScript中面向对象技术的模拟
2006/09/25 Javascript
JavaScript 快捷键设置实现代码
2009/03/13 Javascript
cument.execCommand()用法深入理解
2012/12/04 Javascript
Js 时间函数getYear()的使用问题探讨
2013/04/01 Javascript
javascript中常用编程知识
2013/04/08 Javascript
javascript为下拉列表动态添加数据项
2014/05/23 Javascript
jQuery中:submit选择器用法实例
2015/01/03 Javascript
javascript连续赋值问题
2015/07/08 Javascript
javascript+HTML5的canvas实现七夕情人节3D玫瑰花效果代码
2015/08/04 Javascript
JavaScript中的call方法和apply方法使用对比
2015/08/12 Javascript
微信小程序开发之入门实例教程篇
2017/03/07 Javascript
基于cropper.js封装vue实现在线图片裁剪组件功能
2018/03/01 Javascript
原生JS实现多条件筛选
2020/08/19 Javascript
openlayers实现地图弹窗
2020/09/25 Javascript
解决新版Pycharm中Matplotlib图像不在弹出独立的显示窗口问题
2019/01/15 Python
详解Python Matplot中文显示完美解决方案
2019/03/07 Python
python如何删除文件、目录
2020/06/23 Python
利用keras使用神经网络预测销量操作
2020/07/07 Python
Python中Selenium模块的使用详解
2020/10/09 Python
理肤泉俄罗斯官网:La Roche-Posay俄罗斯
2018/07/24 全球购物
英文版销售经理个人求职信
2013/11/20 职场文书
高级护理专业毕业生推荐信
2013/12/25 职场文书
国际贸易毕业生自荐书
2014/06/22 职场文书
2015新教师教学工作总结
2015/07/22 职场文书
MySQL面试题讲解之如何设置Hash索引
2021/11/01 MySQL