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源代码
Aug 21 PHP
php 获取当前访问的url文件名的方法小结
Feb 08 PHP
php守护进程 加linux命令nohup实现任务每秒执行一次
Jul 04 PHP
php安全之直接用$获取值而不$_GET 字符转义
Jun 03 PHP
通过PHP current函数获取未知字符键名数组第一个元素的值
Jun 24 PHP
destoon在360浏览器下出现用户被强行注销的解决方法
Jun 26 PHP
跟我学Laravel之请求(Request)的生命周期
Oct 15 PHP
php面向对象中static静态属性与方法的内存位置分析
Feb 08 PHP
Ajax PHP JavaScript MySQL实现简易无刷新在线聊天室
Aug 17 PHP
php通过PHPExcel导入Excel表格到MySQL数据库的简单实例
Oct 29 PHP
php 如何禁用eval() 函数实例详解
Dec 01 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实现格式化多行文本为Js可用格式
2015/04/15 PHP
Laravel项目中timeAgo字段语言转换的改善方法示例
2019/09/16 PHP
PHP 计算两个时间段之间交集的天数示例
2019/10/24 PHP
Prototype1.5 rc2版指南最后一篇之Position
2007/01/10 Javascript
javascript showModalDialog 内跳转页面的问题
2010/11/25 Javascript
javascript自适应宽度的瀑布流实现思路
2013/02/20 Javascript
利用JS判断用户是否上网(连接网络)
2013/12/23 Javascript
JavaScript获取Url里的参数
2014/12/18 Javascript
JavaScript中的getTimezoneOffset()方法使用详解
2015/06/10 Javascript
纯js代码制作的网页时钟特效【附实例】
2016/03/30 Javascript
js is_valid_filename验证文件名的函数
2017/07/19 Javascript
javascript实现获取一个日期段内每天不同的价格(计算入住总价格)
2018/02/05 Javascript
js中位运算的运用实例分析
2018/12/11 Javascript
vue中使用elementUI组件手动上传图片功能
2019/12/13 Javascript
Python selenium文件上传方法汇总
2020/11/19 Python
利用TensorFlow训练简单的二分类神经网络模型的方法
2018/03/05 Python
pandas把dataframe转成Series,改变列中值的类型方法
2018/04/10 Python
python使用多线程编写tcp客户端程序
2019/09/02 Python
Python批量处理csv并保存过程解析
2020/05/16 Python
印度最大的酒店品牌网络:OYO Rooms
2016/07/24 全球购物
巴西家用小家电购物网站:Polishop
2016/08/07 全球购物
阿根廷旅游网站:almundo阿根廷
2018/02/12 全球购物
Shopee印度尼西亚:东南亚与台湾市场最大电商平台
2018/06/17 全球购物
韩语专业本科生求职信
2013/10/01 职场文书
有针对性的求职自荐信
2013/11/14 职场文书
自荐信格式写作方法有哪些呢
2013/11/20 职场文书
大学生简历的个人自我评价
2013/12/04 职场文书
小学生中国梦演讲稿
2014/04/23 职场文书
中华美德颂演讲稿
2014/05/20 职场文书
2014年个人工作总结报告
2014/11/27 职场文书
工程部部长岗位职责
2015/02/12 职场文书
边城读书笔记
2015/06/29 职场文书
爱护环境建议书
2015/09/14 职场文书
少先大队干部竞选稿
2015/11/20 职场文书
手把手教你制定暑期学习计划,让你度过充实的暑假
2019/08/22 职场文书
基于Python实现股票收益率分析
2022/04/02 Python