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

  读取大文件一直是一个头痛的问题,我们像使用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;
  // } 

 }
时间: 2024-09-16 09:24:17

PHP读取大文件的几种方法介绍的相关文章

PHP读取大文件的几种方法介绍_php实例

读取大文件一直是一个头痛的问题,我们像使用php开发读取小文件可以直接使用各种函数实现,但一到大文章就会发现常用的方法是无法正常使用或时间太长太卡了,下面我们就一起来看看关于php读取大文件问题解决办法,希望例子能帮助到各位. 场景:PHP读取超大文件,例如1G的日志文件,我这里使用的是400M的access.log文件 1.使用file直接读取 <?php $starttime=microtime_float(); ini_set('memory_limit', '-1'); $file =

asp.net读取excel文件的三种方法示例

 这篇文章主要介绍了asp.net读取excel文件的三种方法示例,包括采用OleDB读取Excel文件.引用的com组件读取Excel文件.用文件流读取,需要的朋友可以参考下 方法一:采用OleDB读取Excel文件   把Excel文件当做一个数据源来进行数据的读取操作,实例如下:  代码如下: public DataSet ExcelToDS(string Path)    {    string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;&q

php读取大文件最好的实现方法

  php读取大文件方法我们一般是一行行来讲取而不是一次性把文件全部写入内存中了,这样会导致php程序卡死,下面给大家整理一个例子.  代码如下   读取大文件最后几行数据: /**  * 取文件最后$n行  * @param string $filename 文件路径  * @param int $n 最后几行  * @return mixed false表示有错误,成功则返回字符串  */ function FileLastLines($filename,$n){     if(!$fp=f

asp.net读取excel文件,哪种方法更优?

问题描述 百度一下,综合有5种方法1.使用OLEDB2.使用Office主互操作程序集3.使用ServerDocument4.使用OpenXMLSDK5.npoi是不是第5种最好.最简单? 解决方案 解决方案二:其实无非2种1.引用office.excel.dll2.第三方dll方法1问题太多,比如部署麻烦,要配置DCOM,设置权限,设置应用程序池位数,而且可能产生excel死进程,服务器上要安装office,而且与dll版本必须一致.....一般都是采用方法2,第三方dll有许多种,NPOI只

读取config文件的两种方法

  项目进入测试阶段,暂时闲下来了,写点笔记. 读取web.config 或者 app.config中自定义配置的值的属性,常用2种方法. 假设有如下配置: <appSettings>  <add key="A" value="config with A"/>  <add key="B" value="config with B"/> </appSettings>  using

.NET读取Excel文件的三种方法的区别_实用技巧

ASP.NET读取Excel文件方法一:采用OleDB读取Excel文件: 把Excel文件当做一个数据源来进行数据的读取操作,实例如下: 复制代码 代码如下: public DataSet ExcelToDS(string Path)   {    string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" +"Data Source="+ Path +";"+"Extended Prop

asp.net读取excel文件的三种方法示例_实用技巧

方法一:采用OleDB读取Excel文件 把Excel文件当做一个数据源来进行数据的读取操作,实例如下: 复制代码 代码如下: public DataSet ExcelToDS(string Path)   {   string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" +"Data Source="+ Path +";"+"Extended Properties=Excel 8.0;&

PHP读取大文件的类SplFileObject使用介绍

 一般读取文件我们用fopen 或者 file_get_contents ,前者可以循环读取,后者可以一次性读取,但都是将文件内容一次性加载来操作. 如果加载的文件特别大时,如几百M,上G时,这时性能就降下来了,那么PHP里有没有对大文件的处理函数或者类呢? 答案是:有的. PHP真的越来越"面向对象"了,一些原有的基础的SPL方法都开始陆续地实现出class了. 从 PHP 5.1.0 开始,SPL 库增加了 SplFileObject 与 SplFileInfo 两个标准的文件操作

PHP读取大文件的类SplFileObject使用介绍_php实例

如果加载的文件特别大时,如几百M,上G时,这时性能就降下来了,那么PHP里有没有对大文件的处理函数或者类呢? 答案是:有的.PHP真的越来越"面向对象"了,一些原有的基础的SPL方法都开始陆续地实现出class了.从 PHP 5.1.0 开始,SPL 库增加了 SplFileObject 与 SplFileInfo 两个标准的文件操作类.SplFileInfo 是从 PHP 5.1.2 开始实现的.从字面意思理解看,可以看出 SplFileObject 要比 SplFileInfo 更