当前位置: 首页 > news >正文

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)

相关文章:

  • sass学习
  • U盘安装Windows 7 + Ubuntu 14 双系统笔记
  • 部署exchange2010三合一:之五:功能测试
  • 一步一步学Ruby(八):字符串表达式
  • 5.4 索引查找
  • Mac Pro 软件收藏
  • Java中的集合框架
  • Redis客户端开发包:Jedis学习-高级应用
  • 读书笔记
  • Python入门之list,tuple,dict,set的区别
  • 用JvisualVM监视远程tomcat
  • Jenkins结合github持续集成环境构建
  • iOS 疑难杂症 — — Swift debugger 无法在控制台 po 变量值的问题
  • Nginx随笔(一):HTTP配置
  • Sublime运行Matlab
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • django开发-定时任务的使用
  • eclipse(luna)创建web工程
  • es6(二):字符串的扩展
  • Git同步原始仓库到Fork仓库中
  • javascript 总结(常用工具类的封装)
  • LeetCode29.两数相除 JavaScript
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • SegmentFault 技术周刊 Vol.27 - Git 学习宝典:程序员走江湖必备
  • vue-cli3搭建项目
  • 构造函数(constructor)与原型链(prototype)关系
  • 开源地图数据可视化库——mapnik
  • 日剧·日综资源集合(建议收藏)
  • 使用权重正则化较少模型过拟合
  • 物联网链路协议
  •  一套莫尔斯电报听写、翻译系统
  • Java数据解析之JSON
  • 仓管云——企业云erp功能有哪些?
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • $.ajax()
  • (poj1.3.2)1791(构造法模拟)
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (转)微软牛津计划介绍——屌爆了的自然数据处理解决方案(人脸/语音识别,计算机视觉与语言理解)...
  • .net oracle 连接超时_Mysql连接数据库异常汇总【必收藏】
  • .Net 应用中使用dot trace进行性能诊断
  • .NET/C# 使窗口永不获得焦点
  • .NET版Word处理控件Aspose.words功能演示:在ASP.NET MVC中创建MS Word编辑器
  • @Responsebody与@RequestBody
  • @WebServiceClient注解,wsdlLocation 可配置
  • [ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例
  • [ 英语 ] 马斯克抱水槽“入主”推特总部中那句 Let that sink in 到底是什么梗?
  • [Asp.net mvc]国际化
  • [BZOJ1178][Apio2009]CONVENTION会议中心
  • [C# WPF] DataGrid选中行或选中单元格的背景和字体颜色修改
  • [CLickhouse] 学习小计
  • [Editor]Unity Editor类常用方法
  • [Flex][问题笔记]TextArea滚动条问题
  • [HackMyVM]靶场 Wild
  • [HNOI2010]BUS 公交线路
  • [JavaScript]_[初级]_[关于forof或者for...of循环语句的用法]