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的宝库目录--PEAR
Oct 09 PHP
PHP垃圾回收机制简单说明
Jul 22 PHP
深入解析PHP内存管理之谁动了我的内存
Jun 20 PHP
PHP迭代器实现斐波纳契数列的函数
Nov 12 PHP
PHP使用GETDATE获取当前日期时间作为一个关联数组的方法
Mar 19 PHP
Laravel 5框架学习之向视图传送数据
Apr 08 PHP
编写PHP脚本过滤用户上传的图片
Jul 03 PHP
几个优化WordPress中JavaScript加载体验的插件介绍
Dec 17 PHP
PHP生成和获取XML格式数据的方法
Mar 04 PHP
PHP实现随机数字、字母的验证码功能
Aug 01 PHP
Laravel 自动生成验证的实例讲解:login / logout
Oct 14 PHP
浅谈如何提高PHP代码质量之单元测试
May 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
ftp类(example.php)
2006/10/09 PHP
Codeigniter实现智能裁剪图片的方法
2014/06/12 PHP
php身份证号码检查类实例
2015/06/18 PHP
PHP合并discuz用户脚本的方法
2015/08/04 PHP
浅析php中array_map和array_walk的使用对比
2016/11/20 PHP
php查找字符串中第一个非0的位置截取
2017/02/27 PHP
js jquery做的图片连续滚动代码
2008/01/06 Javascript
javascript 面向对象编程基础 多态
2009/08/21 Javascript
网页右键ie不支持event.preventDefault和event.returnValue (需要加window)
2013/02/22 Javascript
使用javascript过滤html的字符串(注释标记法)
2013/07/08 Javascript
JavaScript从数组中删除指定值元素的方法
2015/03/18 Javascript
jQuery获取页面及个元素高度、宽度的总结——超实用
2015/07/28 Javascript
jQuery仿淘宝网产品品牌隐藏与显示效果
2015/09/01 Javascript
JS数组去重的6种方法完整实例
2018/12/08 Javascript
JavaScript中AOP的实现与应用
2019/05/06 Javascript
JS自定义滚动条效果
2020/03/13 Javascript
H5 js点击按钮复制文本到粘贴板
2020/11/19 Javascript
Python解惑之True和False详解
2017/04/24 Python
基于python元祖与字典与集合的粗浅认识
2017/08/23 Python
Python实现嵌套列表及字典并按某一元素去重复功能示例
2017/11/30 Python
Pandas 数据处理,数据清洗详解
2018/07/10 Python
Python中psutil的介绍与用法
2019/05/02 Python
python 在某.py文件中调用其他.py内的函数的方法
2019/06/25 Python
详解如何从TensorFlow的mnist数据集导出手写体数字图片
2019/08/05 Python
关于Python形参打包与解包小技巧分享
2019/08/24 Python
使用Python代码实现Linux中的ls遍历目录命令的实例代码
2019/09/07 Python
python3.7通过thrift操作hbase的示例代码
2020/01/14 Python
杭州联环马网络笔试题面试题
2013/08/04 面试题
20岁生日感言
2014/01/13 职场文书
商务英语专业求职信范文
2014/01/28 职场文书
绿色学校实施方案
2014/03/31 职场文书
大学教师个人总结
2015/02/10 职场文书
自主招生自荐信格式范文
2015/03/25 职场文书
互联网的下一个风口:新的独角兽将诞生
2019/08/02 职场文书
变长双向rnn的正确使用姿势教学
2021/05/31 Python
「回转企鹅罐」10周年纪念展「輪るピングドラム展」海报公开
2022/03/22 日漫