>백엔드 개발 >PHP 튜토리얼 >PHP如何快速读取大文件_PHP教程

PHP如何快速读取大文件_PHP教程

WBOY
WBOY원래의
2016-07-13 10:17:23919검색

PHP如何快速读取大文件

在PHP中,对于文件的读取时,最快捷的方式莫过于使用一些诸如filefile_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读取目录并列表显示目录中的文件的函数
  • php读取xml文件总结
  • PHP 利用 Curl Functions 实现多线程抓取网页和下载文件
  • php error_log() 将错误信息写入一个文件
  • PHP对变量进行序列化的方法大比拼 php四种序列化变量的方法
  • 使用PHP的GZip压缩功能对网站JS和CSS文件进行压缩加速网站访问速度
  • PHP删除目录及目录下所有文件
  • 如何解决php中并发读写文件冲突的问题

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/892950.htmlTechArticlePHP如何快速读取大文件 在PHP中,对于文件的读取时,最快捷的方式莫过于使用一些诸如 file 、 file_get_contents 之类的函数,简简单单的几行...
성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.