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 session应用实例 登录验证
Mar 16 PHP
php file_put_contents()功能函数(集成了fopen、fwrite、fclose)
May 24 PHP
PHP curl_setopt()函数实例代码与参数分析
Jun 02 PHP
php更新mysql后获取改变行数的方法
Dec 25 PHP
PHP中使用php://input处理相同name值的表单数据
Feb 03 PHP
php实现上传图片保存到数据库的方法
Feb 11 PHP
php通过curl模拟登陆DZ论坛
May 11 PHP
php readfile()修改文件上传大小设置
Aug 11 PHP
php微信开发之关注事件
Jun 14 PHP
浅谈laravel5.5 belongsToMany自身的正确用法
Oct 17 PHP
PHP Swoole异步MySQL客户端实现方法示例
Oct 24 PHP
php 下 html5 XHR2 + FormData + File API 上传文件操作实例分析
Feb 28 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
使用xampp搭建运行php虚拟主机的详细步骤
2015/10/21 PHP
thinkphp集成前端脚手架Vue-cli的教程图解
2018/08/30 PHP
JavaScript 学习笔记(五)
2009/12/31 Javascript
网页加载时页面显示进度条加载完成之后显示网页内容
2012/12/23 Javascript
javascript匿名函数实例分析
2014/11/18 Javascript
SeaJS 与 RequireJS 的差异对比
2014/12/08 Javascript
项目中常用的JS方法整理
2015/01/30 Javascript
jquery 构造函数在表单提交过程中修改数据
2015/05/25 Javascript
jQuery左侧大图右侧小图焦点图幻灯切换代码分享
2015/08/19 Javascript
比较常见的javascript中定义函数的区别
2015/11/09 Javascript
原生JavaScript实现异步多文件上传
2015/12/02 Javascript
分享JavaScript与Java中MD5使用两个例子
2015/12/23 Javascript
Angular.js与Bootstrap相结合实现表格分页代码
2016/04/12 Javascript
javascript时间差插件分享
2016/07/18 Javascript
Web前端开发之水印、图片验证码
2016/11/27 Javascript
jQuery动画_动力节点节点Java学院整理
2017/07/04 jQuery
vue 音乐App QQ音乐搜索列表最新接口跨域设置方法
2018/09/25 Javascript
vue从零实现一个消息通知组件的方法详解
2020/03/16 Javascript
详解python调度框架APScheduler使用
2017/03/28 Python
Python基于matplotlib绘制栈式直方图的方法示例
2017/08/09 Python
Python实现在线暴力破解邮箱账号密码功能示例【测试可用】
2017/09/06 Python
Python运维自动化之nginx配置文件对比操作示例
2018/08/29 Python
面向对象学习之pygame坦克大战
2019/09/11 Python
Python使用matplotlib 模块scatter方法画散点图示例
2019/09/27 Python
python中time库的实例使用方法
2019/10/31 Python
python滑块验证码的破解实现
2019/11/10 Python
python为Django项目上的每个应用程序创建不同的自定义404页面(最佳答案)
2020/03/09 Python
css3类选择器之结合元素选择器和多类选择器用法
2017/03/09 HTML / CSS
美国在线珠宝商店:SZUL
2017/02/11 全球购物
城野医生官方海外旗舰店:风靡亚洲毛孔收敛水
2018/04/26 全球购物
澳大利亚鞋仓库:Shoe Warehouse
2019/07/25 全球购物
企业业务员岗位职责
2014/03/14 职场文书
食品流通安全承诺书
2014/05/22 职场文书
护士节活动总结
2014/08/29 职场文书
党政领导班子四风问题对照检查材料思想汇报
2014/10/02 职场文书
幼儿园万圣节活动总结
2015/05/05 职场文书