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 相关文章推荐
非常不错的MySQL优化的8条经验
Mar 24 PHP
fgetcvs在linux的问题
Jan 15 PHP
10 个经典PHP函数
Oct 17 PHP
PHP制作图形验证码代码分享
Oct 23 PHP
3种php生成唯一id的方法
Nov 23 PHP
php使用pear_smtp发送邮件
Apr 15 PHP
php字符串比较函数用法小结(strcmp,strcasecmp,strnatcmp及strnatcasecmp)
Jul 18 PHP
ThinkPHP3.1.x修改成功与失败跳转页面的方法
Sep 29 PHP
利用PHP实现开心消消乐的算法示例
Oct 12 PHP
Laravel中的chunk组块结果集处理与注意问题
Aug 15 PHP
laravel5.1框架model类查询的实现方法
Oct 08 PHP
phpquery中文手册
Mar 18 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屏蔽蜘蛛访问代码及常用搜索引擎的HTTP_USER_AGENT
2013/03/06 PHP
php解析xml 的四种简单方法(附实例)
2016/07/11 PHP
PDO操作MySQL的基础教程(推荐)
2017/08/18 PHP
Laravel 模型关联基础教程详解
2019/09/17 PHP
让您的菜单不离网站
2006/10/03 Javascript
jquery 表单取值常用代码
2009/12/22 Javascript
JS input文本框禁用右键和复制粘贴功能的代码
2010/04/15 Javascript
jquery提升性能最佳实践小结
2010/12/06 Javascript
写js时遇到的一些小问题
2010/12/06 Javascript
jquery 操作DOM案例代码分享
2012/04/05 Javascript
在浏览器窗口上添加遮罩层的方法
2012/11/12 Javascript
js禁止页面使用右键(简单示例代码)
2013/11/13 Javascript
jQuery对下拉框,单选框,多选框的操作
2014/02/21 Javascript
jQuery中ready事件用法实例
2015/01/19 Javascript
JavaScript实现模仿桌面窗口的方法
2015/07/18 Javascript
js判断上传文件后缀名是否合法
2016/01/28 Javascript
利用node.js制作命令行工具方法教程(一)
2017/06/22 Javascript
jquery 一键复制到剪切板的实例
2017/09/20 jQuery
JS脚本加载后执行相应回调函数的操作方法
2018/02/28 Javascript
jquery实现动态改变css样式的方法分析
2019/05/27 jQuery
Javascript模拟实现new原理解析
2020/03/03 Javascript
[06:53]2018DOTA2国际邀请赛寻真——为复仇而来的Newbee
2018/08/15 DOTA
Python实现字符串格式化的方法小结
2017/02/20 Python
Python多层装饰器用法实例分析
2018/02/09 Python
使用Python来开发微信功能
2018/06/13 Python
Python面向对象之Web静态服务器
2019/09/03 Python
给 TensorFlow 变量进行赋值的方式
2020/02/10 Python
理肤泉加拿大官网:La Roche-Posay加拿大
2018/07/06 全球购物
改变生活的男士内衣:SAXX Underwear
2019/08/28 全球购物
精通CAD能手自荐书
2014/01/31 职场文书
乡镇庆八一活动方案
2014/02/02 职场文书
如何写好建议书
2014/03/13 职场文书
户籍证明书标准模板
2014/09/10 职场文书
导师工作推荐信
2015/03/27 职场文书
圆明园观后感
2015/06/03 职场文书
利用Matlab绘制各类特殊图形的实例代码
2021/07/16 Python