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

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

场景:PHP读取超大文件,例如1G的日志文件,我这里使用的是400M的access.log文件

1、使用file直接读取

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
$starttime =microtime_float();
  
ini_set ( 'memory_limit' , '-1' );
$file = 'testfile.txt' ;
  
$data = file( $file );
$line = $data [ count ( $data ) - 1000];
$endtime =microtime_float();
  
echo count ( $data ), "<br/>" ;
echo $endtime - $starttime ;
  
function microtime_float(){
  list( $usec , $sec ) = explode ( " " , microtime());
  return ((float) $usec + (float) $sec );
}
?>

运行结果:10127784 行   共使用了,7.8764359951s

我的电脑是3G内存,此方法不是推荐使用,因为需要把文件全部载入内存

2、使用linux命令  tail

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
  
$starttime =microtime_float();
  
$file = 'testfile.txt' ;
$file = escapeshellarg ( $file ); // 对命令行参数进行安全转义
$line = `tail -n 100 $file `;
  
echo $line , "<br/>" ;
  
$endtime =microtime_float();
echo $endtime - $starttime ;
  
function microtime_float(){
  list( $usec , $sec ) = explode ( " " , microtime());
  return ((float) $usec + (float) $sec );
}
  
//end

运行结果:只使用了几毫秒、轻松搞定、这种方法不能在windows下使用

3、使用fseek函数

这种方式是最为普遍的方式,它不需要将文件的内容全部读入内容,因为PHP是C写的,所以实现的时候也类似C读取文件,通过指针的移动,所以效率是相当高效的。在使用fseek来对文件进行操作时,也有多种不同的方法,效率可能也是略有差别的,

下面是常用的几种方法

方法一:使用fopen打开文件(从文件指针资源句柄)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
$starttime =microtime_float();
  
$file = 'testfile.txt' ;
$fp = fopen ( $file , "r+" );
  
$line = 100;
$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 , "<br/>" ;
$endtime =microtime_float();
  
echo $endtime - $starttime ;
  
function microtime_float(){
  list( $usec , $sec ) = explode ( " " , microtime());
  return ((float) $usec + (float) $sec );
}
?>

运行结果:0.338493108749

方法二:一块一块的读取

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
$starttime =microtime_float();
  
$file = 'testfile.txt' ;
$fp = fopen ( $file , "r" );
$num = 10;
$chunk = 4096; //4K的块
$fs = sprintf( "%u" , filesize ( $file ));
$readData = '' ;
$max = ( intval ( $fs ) == PHP_INT_MAX) ? PHP_INT_MAX : $fs ;
  
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) {
  
  $ns =substr_count( $readData , "\n" )- $num +2;
  preg_match( '/(.*?\n){' . $ns . '}/' , $readData , $match );
  $data = $match [1];
  break ;
}
}
fclose( $fp );
echo $data , "<br/>" ;
  
  
$endtime =microtime_float();
  
echo $endtime - $starttime ;
  
function microtime_float(){
  list( $usec , $sec ) = explode ( " " , microtime());
  return ((float) $usec + (float) $sec );
}
?>

运行时间:0.00199198722839

使用fgets函数,一行一行读取

?
1
2
3
4
5
6
7
<?php
$file = fopen ( "testfile.txt" , "r" );
  while (! feof ( $file ))
  {
    echo fgets ( $file );
  }
  fclose( $file );

spl库函数

?
1
2
3
4
5
6
7
<?php
try {
   foreach ( new SplFileObject( 'testfile.txt' ) as $line )
   echo $line . '<br />' ;
} catch (Exception $e ){
   echo $e ->getMessage();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值