一道PHP题,请问谁能给解释一下?

一道PHP题,请问谁能给解释一下?,第1张

<?

function pathconvert($cur,$absp)//当前文件,目标路径

{

$cur=str_replace('\\','/',$cur)

$absp=str_replace('\\','/',$absp)

$sabsp=explode('/',$absp)

$scur=explode('/',$cur)

$la=count($sabsp)-1

$lc=count($scur)-1

$l=max($la,$lb)

for($i=0$i<=$l$i++){

if($sabsp[$i]!=$scur[$i])

break

}

$k=$i-1

$path=""

for($i=1$i<=($lc-$k-1)$i++)

$path.="../"

for($i=$k+1$i<=($la-1)$i++)

$path.=$sabsp[$i]."/"

$path.=$sabsp[$la]

return$path

}

$path=pathconvert("/home/web/test/a.php","/home/data/d.png")

echo $path

?>

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

需求

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

实现方法

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

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

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

整个代码执行完成耗时 116.9613 (s).

$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

我机器是2个G的内存,当按下F5运行时,系统直接变灰,差不多20分钟后才恢复过来,可见将这么大的文件全部直接读入内存,后果是多少严重,所以不在万不得以,memory_limit这东西不能调得太高,否则只有打电话给机房,让reset机器了.

2.直接调用linux的tail命令来显示最后几行

在linux命令行下,可以直接使用tail -n 10 access.log很轻易的显示日志文件最后几行,可以直接用php来调用tail命令,执行php代码如下.

整个代码执行完成耗时 0.0034 (s)

file = 'access.log'

$file = escapeshellarg($file)// 对命令行参数进行安全转义

$line = `tail -n 1 $file`

echo $line

3. 直接使用php的fseek来进行文件 *** 作

这种方式是最为普遍的方式,它不需要将文件的内容全部读入内容,而是直接通过指针来 *** 作,所以效率是相当高效的.在使用fseek来对文件进行 *** 作时,也有多种不同的方法,效率可能也是略有差别的,下面是常用的两种方法.

方法一

首先通过fseek找到文件的最后一位EOF,然后找最后一行的起始位置,取这一行的数据,再找次一行的起始位置,再取这一行的位置,依次类推,直到找到了$num行。

实现代码如下

整个代码执行完成耗时 0.0095 (s)

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))

方法二

还是采用fseek的方式从文件最后开始读,但这时不是一位一位的读,而是一块一块的读,每读一块数据时,就将读取后的数据放在一个buf里,然后通过换行符(n)的个数来判断是否已经读完最后$num行数据.

实现代码如下

整个代码执行完成耗时 0.0009(s).

$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.0003(s)

ini_set('memory_limit','-1')

$file = 'access.log'

$data = file($file)

$line = $data[count($data)-1]

echo $line

php压缩HTML函数轻松实现压缩html/js/Css及注意事项 phpexcel导出excel的颜色和网页中的颜色显示不一致


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12031345.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-20
下一篇 2023-05-20

发表评论

登录后才能评论

评论列表(0条)

保存