PHP读取大文件的多种方法介绍


Posted in PHP onApril 04, 2016

读取大文件一直是一个头痛的问题,我们像使用php开发读取小文件可以直接使用各种函数实现,但一到大文章就会发现常用的方法是无法正常使用或时间太长太卡了,下面我们就一起来看看关于php读取大文件问题解决办法,希望例子能帮助到各位。

在PHP中,对于文件的读取时,最快捷的方式莫过于使用一些诸如file、file_get_contents之类的函数,简简单单的几行代码就能 很漂亮的完成我们所需要的功能。但当所操作的文件是一个比较大的文件时,这些函数可能就显的力不从心, 下面将从一个需求入手来说明对于读取大文件时,常用的操作方法。

需求:
有一个800M的日志文件,大约有500多万行, 用PHP返回最后几行的内容。

实现方法:

1. 直接采用file函数来操作

由于 file函数是一次性将所有内容读入内存,而PHP为了防止一些写的比较糟糕的程序占用太多的内存而导致系统内存不足,使服务器出现宕机,所以默认情况下限制只能最大使用内存16M,这是通过php.ini里的 memory_limit = 16M 来进行设置,这个值如果设置-1,则内存使用量不受限制。

下面是一段用file来取出这具文件最后一行的代码:

<?php
ini_set('memory_limit', '-1');
$file = 'access.log';
$data = file($file);
$line = $data[count($data) - 1];
echo $line;
?>

整个代码执行完成耗时 116.9613 (s)。

我机器是2个G的内存,当按下F5运行时,系统直接变灰,差不多20分钟后才恢复过来,可见将这么大的文件全部直接读入内存,后果是多少严重,所以不在万 不得以,memory_limit这东西不能调得太高,否则只有打电话给机房,让reset机器了。

2.直接调用Linux的 tail 命令来显示最 后几行

在Linux命令行下,可以直接使用 tail -n 10 access.log 很轻易的显示日志文件最后几行,可以直接用PHP来调用tail命令,执行PHP代码如下:

<?php
  $file = 'access.log';
  $file = escapeshellarg($file); // 对命令行参数进行安全转义
  $line = `tail -n 1 $file`;
  echo $line;
?>

整个代码执行完成耗时 0.0034 (s)

3. 直接使用PHP的 fseek 来进行文件操作

这种方式是最为普遍的方式,它不需要将文件的内容全部读入内容,而是直接通过指针来操作,所以效率是相当高效的。在使用fseek来对文件进行操作时,也有多种不同的方法,效率可能也是略有差别的,下面是常用的两种方法:

方法一

首先通过fseek找到文件的最后一位EOF,然后找最后一行的起始位置,取这一行的数据,再找次一行的起始位置, 再取这一行的位置,依次类推,直到找到了$num行。
实现代码如下

<?php
$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.0095 (s)

方法二

还是采用fseek的方式从文件最后开始读,但这时不是一位一位的读,而是一块一块的读,每读一块数据时,就将读取后的数据放在一个buf里,然后通过换 行符(\n)的个数来判断是否已经读完最后$num行数据。
实现代码如下

<?php
$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;
?>

整个代码执行完成耗时 0.0009(s)。

方法三

<?php
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));
?>

整个代码执行完成耗时 0.0003(s)

方法四,PHP的stream_get_line函数 ,读取快速,读取50万条数据大文件,大概需要20秒左右的时间!例子代码如下

$fp = fopen('./iis.log', 'r'); //文件 
while (!feof($fp)) { 
 //for($j=1;$j<=1000;$j++) {     //读取下面的1000行并存储到数组中 
 $logarray[] = stream_get_line($fp, 65535, "\n"); 
    // break;
 // } 
 
 }

以上就是php读取大文件的四种方法,希望对大家的学习有所帮助。

PHP 相关文章推荐
输出控制类
Oct 09 PHP
PHP读MYSQL中文乱码的解决方法
Dec 17 PHP
简单的移动设备检测PHP脚本代码
Feb 19 PHP
解析php中用PHPMailer来发送邮件的示例(126.com的例子)
Jun 24 PHP
php中mysql连接方式PDO使用详解
Feb 25 PHP
PHP+MySql+jQuery实现的&quot;顶&quot;和&quot;踩&quot;投票功能
May 21 PHP
PHP中set_include_path()函数相关用法分析
Jul 18 PHP
基于PHP实现用户注册登录功能
Oct 14 PHP
Zend Framework前端控制器用法示例
Dec 11 PHP
AJAX的使用方法详解
Apr 29 PHP
PHP实现的登录页面信息提示功能示例
Jul 24 PHP
php检查函数必传参数是否存在的实例详解
Aug 28 PHP
PHP如何将XML转成数组
Apr 04 #PHP
php自动加载方式集合
Apr 04 #PHP
php文件上传的两种实现方法
Apr 04 #PHP
在Win2003(64位)中配置IIS6+PHP5.2.17+MySQL5.5的运行环境
Apr 04 #PHP
PHP版本的选择5.2.17 5.3.27 5.3.28 5.4 5.5兼容性问题分析
Apr 04 #PHP
PHP命名空间和自动加载类
Apr 03 #PHP
PHP中的Trait 特性及作用
Apr 03 #PHP
You might like
杏林同学录(一)
2006/10/09 PHP
PHP简单系统数据添加以及数据删除模块源文件下载
2008/06/07 PHP
thinkPHP数据查询常用方法总结【select,find,getField,query】
2017/03/15 PHP
jQuery ajax在GBK编码下表单提交终极解决方案(非二次编码方法)
2010/10/20 Javascript
Jquery 数据选择插件Pickerbox使用介绍
2012/08/24 Javascript
jquery scrollTop方法根据滚动像素显示隐藏顶部导航条
2013/05/27 Javascript
js为数字添加逗号并格式化数字的代码
2013/08/23 Javascript
Javascript 实现的数独解题算法网页实例
2013/10/15 Javascript
JS保留两位小数,多位小数的示例代码
2014/01/07 Javascript
node.js中的http.response.write方法使用说明
2014/12/14 Javascript
js闭包所用的场合以及优缺点分析
2015/06/22 Javascript
在JavaScript中call()与apply()区别
2016/01/22 Javascript
jQuery ztree实现动态树形多选菜单
2016/08/12 Javascript
angular5 httpclient的示例实战
2018/03/12 Javascript
详解在Vue中使用TypeScript的一些思考(实践)
2018/07/06 Javascript
详解在React中跨组件分发状态的三种方法
2018/08/09 Javascript
node crawler如何添加promise支持
2020/02/01 Javascript
详解vue-flickity的fullScreen功能实现
2020/04/07 Javascript
JavaScript事件委托实现原理及优点进行
2020/08/29 Javascript
vue实现桌面向网页拖动文件的示例代码(可显示图片/音频/视频)
2021/03/01 Vue.js
安装Python的教程-Windows
2017/07/22 Python
关于Python如何避免循环导入问题详解
2017/09/14 Python
Python 逐行分割大txt文件的方法
2017/10/10 Python
python PrettyTable模块的安装与简单应用
2019/01/11 Python
利用Python实现Shp格式向GeoJSON的转换方法
2019/07/09 Python
pytest中文文档之编写断言
2019/09/12 Python
Python3标准库之functools管理函数的工具详解
2020/02/27 Python
Python3 requests模块如何模仿浏览器及代理
2020/06/15 Python
Python爬虫逆向分析某云音乐加密参数的实例分析
2020/12/04 Python
selenium如何定位span元素的实现
2021/01/13 Python
英超联赛的首选足球:Mitre足球
2019/05/06 全球购物
一套Delphi的笔试题一
2016/02/14 面试题
省文明单位申报材料
2014/05/08 职场文书
2014年学习厉行节约反对浪费思想汇报
2014/09/10 职场文书
合作经营协议书范本
2014/09/16 职场文书
公安机关正风肃纪剖析材料
2014/10/10 职场文书