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 相关文章推荐
php基础知识:类与对象(2) 自动加载对象
Dec 13 PHP
新手学PHP之数据库操作详解及乱码解决!
Jan 02 PHP
提高PHP编程效率 引入缓存机制提升性能
Feb 15 PHP
php in_array 函数使用说明与in_array需要注意的地方说明
Apr 13 PHP
PHP文章采集URL补全函数(FormatUrl)
Aug 02 PHP
php打开文件fopen函数的使用说明
Jul 05 PHP
thinkphp备份数据库的方法分享
Jan 04 PHP
php获取错误信息的方法
Jul 17 PHP
PHP生成随机密码方法汇总
Aug 27 PHP
php实现网站留言板功能
Nov 04 PHP
PHP载入图像imagecreatefrom_gif_jpeg_png系列函数用法分析
Nov 14 PHP
PHP5.5安装PHPRedis扩展及连接测试方法
Jan 22 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
php 小乘法表实现代码
2009/07/16 PHP
PHP中数组的三种排序方法分享
2012/05/07 PHP
Windows下部署Apache+PHP+MySQL运行环境实战
2012/08/31 PHP
php检测网页是否被百度收录的函数代码
2013/10/09 PHP
PHP使用DirectoryIterator显示下拉文件列表的方法
2015/03/13 PHP
PHP实现GIF图片验证码
2015/11/04 PHP
php.ini中date.timezone设置详解
2016/11/20 PHP
利用onresize使得div可以随着屏幕大小而自适应的代码
2010/01/15 Javascript
表单JS弹出填写提示效果代码
2011/04/16 Javascript
深入了解Node.js中的一些特性
2014/09/25 Javascript
分享Javascript实用方法二
2015/12/13 Javascript
基于javascript实现全国省市二级联动下拉选择菜单
2016/01/28 Javascript
Javascript基础_简单比较undefined和null 值
2016/06/14 Javascript
D3.js封装文本实现自动换行和旋转平移等功能
2016/10/14 Javascript
利用Angular.js限制textarea输入的字数
2016/10/20 Javascript
微信小程序  Mustache语法详细介绍
2016/10/27 Javascript
TypeScript入门-接口
2017/03/30 Javascript
详解关于element级联选择器数据回显问题
2019/02/20 Javascript
layer提示框添加多个按钮选择的实例
2019/09/12 Javascript
vue界面发送表情的实现代码
2020/09/11 Javascript
OpenLayers3实现鼠标移动显示坐标
2020/09/25 Javascript
python实现数通设备tftp备份配置文件示例
2014/04/02 Python
Python爬取数据并写入MySQL数据库的实例
2018/06/21 Python
python批量处理txt文件的实例代码
2020/01/13 Python
Python grpc超时机制代码示例
2020/09/14 Python
python 实现一个图形界面的汇率计算器
2020/11/09 Python
CSS3实现线性渐变用法示例代码详解
2020/08/07 HTML / CSS
俄罗斯化妆品和香水网上商店:Iledebeaute
2019/01/03 全球购物
实习生自荐信范文分享
2013/11/27 职场文书
网上快餐厅创业计划书
2014/02/01 职场文书
会计电算化大学生职业规划书
2014/02/05 职场文书
乡镇办公室工作决心书
2014/03/11 职场文书
公司总经理岗位职责
2014/03/15 职场文书
2015毕业实习推荐信
2015/03/23 职场文书
2015年酒店销售部工作总结
2015/07/24 职场文书
C#连接ORACLE出现乱码问题的解决方法
2021/10/05 Oracle