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

墨初学习笔记1744

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

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

需求:

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

实现方法:

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

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

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

<?phpini_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)。

方法三

<?phpfunction 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读取大文件的四种方法,希望对大家的学习有所帮助。

相关文章

500 501 502 503 504 505 详解

500 501 502 503 504 505 详解

服务器会经常的出现错误,那么在平时的时候出现了服务器错误,我们要如何去解决了,今天小编就简单的说说服务器500错误、501错误、502错误、503错误、504错误、505错误的一些问题所在。服务器50...

PHP 字符串计算 strlen、strpos 与 strrpos 函数

今天无聊一直逛PHP的论坛,顺便弄点有用的东西保存下来,正好很多时间没有更新博客了,今天说说PHP中一些字符串计算的函数,如果我说的不对,还请大神们在下方的评论处留言,并指正一二。计算字符串的长度或定...

CMS建站教程(一)

CMS建站教程(一)

这一段时间一直在大淘客的官方群里混,看到了很多新手想建立一个基于大淘宝CMS的网站,来推广淘宝,天猫的商品获取一部份佣金。但是对于一个不会建站的新手小白来说,难度是很大的。那么从今天开始,我教大家一步...

这个函数返回的是包含当前函数所有参数的一个数组

这个函数返回的是包含当前函数所有参数的一个数组

在PHP中,系统内置好了很多的函数,在我们写PHP程序的过程中可以调用这些函数,可以极大的减少我们开发程序的时间与精力。当然我们也可以自己写函数,PHP在我们的自定义函数中也有系统内置好的系统函数.....

PHP中include()与require()的区别说明(一)

require 的使用方法如 require("xxx.php"); 。这个函数通常放在 PHP 程序的最前面,PHP 程序在执行前,就会先读入 require 所指定引入的文件,...

2017、喜迎2018,愿大家生活,工作双丰收!

2017、喜迎2018,愿大家生活,工作双丰收!

从博客的开通到今天,屈指算来差不多已经五百多个日夜了,而博客才八十多篇文章,平均下来一个星期才发一篇,而文章的主题大多都是技术型或平时记录的东西。通过这一点才充份的证明自己是一个多么懒的人。现在时间是...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。