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代码如下:
整个代码执行完成耗时 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如何快速读取大文件
在PHP中,对于文件的读取时,最快捷的方式莫过于使用一些诸如file.file_get_contents之类的函数,简简单单的几行代码就能 很漂亮的完成我们所需要的功能.但当所操作的文件是一个比较大的 ...
- java读取大文件
1 多线程 2 java内存映射读取大文件
- php使用file函数、fseek函数读取大文件效率分析
php读取大文件可以使用file函数和fseek函数,但是二者之间效率可能存在差异,本文章向大家介绍php file函数与fseek函数实现大文件读取效率对比分析,需要的朋友可以参考一下. 1. 直接 ...
- Java多线程读取大文件
前言 今天是五一假期第一天,按理应该是快乐玩耍的日子,但是作为一个北漂到京师的开发人员,实在难想出去那玩耍.好玩的地方比较远,近处又感觉没意思.于是乎,闲着写篇文章,总结下昨天写的程序吧. 昨天下午朋 ...
- PHP读取大文件的几种方法介绍
读取大文件一直是一个头痛的问题,我们像使用php开发读取小文件可以直接使用各种函数实现,但一到大文章就会发现常用的方法是无法正常使用或时间太长太卡了,下面我们就一起来看看关于php读取大文件问题解决办 ...
- Java 读取大文件方法
需求:实际开发中读取文本文件的需求还是很多,如读取两个系统之间FTP发送文件,读取后保存到数据库中或日志文件的数据库中保存等. 为了测试首先利用数据库SQL生成大数据文件. 规则是 编号|姓名|手机号 ...
- Java高效读取大文件
1.概述 本教程将演示如何用Java高效地读取大文件.这篇文章是Baeldung (http://www.baeldung.com/) 上“Java——回归基础”系列教程的一部分. 2.在内存中读取 ...
- Python逐块读取大文件行数的代码 - 为程序员服务
Python逐块读取大文件行数的代码 - 为程序员服务 python数文件行数最简单的方法是使用enumerate方法,但是如果文件很大的话,这个方法就有点慢了,我们可以逐块的读取文件的内容,然后按块 ...
- Java高效读取大文件(转)
1.概述 本教程将演示如何用Java高效地读取大文件.这篇文章是Baeldung(http://www.baeldung.com/) 上“Java——回归基础”系列教程的一部分. 2.在内存中读取 读 ...
- Python读取大文件的"坑“与内存占用检测
python读写文件的api都很简单,一不留神就容易踩"坑".笔者记录一次踩坑历程,并且给了一些总结,希望到大家在使用python的过程之中,能够避免一些可能产生隐患的代码. 1. ...
随机推荐
- java线程高并发编程
java线程具体解释及高并发编程庖丁解牛 线程概述: 祖宗: 说起java高并发编程,就不得不提起一位老先生Doug Lea,这位老先生可不得了.看看百度百科对他的评价,一点也不为过: 假设IT的历史 ...
- Spring 一二事(9) - xml 形式的 AOP
AOP在spring中是非常重要的一个 在切面类中,有5种通知类型: aop:before 前置通知 aop:after-returning 后置通知 aop:after 最终通知 aop:af ...
- [svc][op]vim自动添加注释
我想了下,要做好一件事, 1,首先喜欢它最才有动机去了解它 2,道听途说about那东西的,会去了解并去玩转 3,兴趣需要培养 一 添加vim头部信息. 系统:C67 追加以下代码到 /etc/vim ...
- 【Android】Java堆栈溢出的解决办法
分类:C#.Android.VS2015: 创建日期:2016-03-18 随着项目中添加的.jar和.so文件越来越多,编译MyDemos项目时,可能会出现Java堆栈溢出的错误,提示让增加Java ...
- linux 双显卡问题。。。
bumblebee的作用是禁用nvidia独立显卡,需要使用独显时,使用”optirun 程序名“手动开启nvidia来运行需要加速的程序,如optirun vmware. 打开N卡设置: optir ...
- u-boot mkconfig文件分析
#!/bin/sh -e #遇到非0返回 就退出脚本 # Script to create header files and links to configure # U-Boot for a spe ...
- HttpWebRequest类与HttpRequest类的区别
HttpRequest类的对象用于服务器端,获取客户端传来的请求的信息,包括HTTP报文传送过来的所有信息.而HttpWebRequest用于客户端,拼接请求的HTTP报文并发送等. HttpWebR ...
- Java 验证码识别之多线程打码兔
验证码识别,爬虫永远的话题~ 用打码兔总体的体验就是单线程速度太慢~ import java.io.IOException; import java.net.MalformedURLException ...
- Android开发日记(一)
实现点击一个图片按钮跳转到一个动作ImageViewSchoolCard = (ImageView) view.findViewById(R.id.ImageViewLostThings); Imag ...
- C#类的修饰符
## C#类的修饰符------------------------- public 任何地方可以调用- internal 同一应用程序集内使用- partial 部分类,一个类分成几部分写在不同文件 ...