SplFileObject将指针移动到上一行

时间:2013-02-20 16:27:56

标签: php logging iteration text-files

所以我正在为自己做一个小实验,一个脚本来读取php错误的日志文件(使用SplFileObject)并在浏览器上输出格式。

我虽然以相反的顺序显示它会更加逻辑(最新的错误在顶部)。 要使用“正常”顺序,我只显示每一行并调用$ file-> next();移动指针,但正如我在反过来做的那样,据我所知,没有prev()previous()方法,我找到的唯一方法是使用{{1} }:

seek()

但这非常慢(对于16mb文件大约7秒)。如果我按照正常的顺序进行,那就是即时的。

有谁知道任何方法?或者我想做的是疯了吗? xD我只是一个被迫编写代码的设计师,所以我对指针和类似的东西不是很熟悉。

3 个答案:

答案 0 :(得分:2)

来自PHP DOC

  

prev - 倒回内部数组指针
  prev()的行为与next()类似,不同之处在于它将内部数组指针倒回一个位置,而不是将其推进。

正如您所看到的,它们只能使用数组而不是文件指针....您只能像这样使用它

$file = new SplFileObject("log.txt", "r");
$file  = iterator_to_array($file);

echo current($file), PHP_EOL;
echo next($file), PHP_EOL;
echo prev($file), PHP_EOL;

如果您想转到下一行,可以尝试使用SplFileObject::ftell获取之前的位置,然后使用SplFileObject::fseek来实现您的反向...

示例

$file = new ReverseableSplFileObject("log.txt", "r");
foreach ( $file as $c ) {
    echo $c, PHP_EOL;
}
echo $file->prev(), PHP_EOL;
echo $file->prev(), PHP_EOL;
echo $file->prev(), PHP_EOL;

输出

A
B
C
C
B
A

修改后的课程

class ReverseableSplFileObject extends SplFileObject {
    private $pos = array();

    function current() {
        return trim(parent::current());
    }

    function next() {
        $this->eof() or $this->pos[] = $this->ftell();
        return parent::next();
    }

    function prev() {
        if (empty($this->pos)) {
            $this->fseek(0);
        } else {
            $this->fseek(array_pop($this->pos));
        }
        return $this->current();
    }
}

答案 1 :(得分:2)

如果将来有人遇到这个问题,我想出了一个非常简单的解决方案:

//get to the last position of the file and get the pointer position.
$content->seek($content->getSize());
$lines_total = $content->key();
$byte = $content->ftell();

//all the line in the php error log starts like: [21-Feb-2013 22:34:53 UTC] so...
$pattern = '/^\[.*\]/';

for(...){
//get the current output to preg_match it
    $data = $content->current();

//go backward each time it doesnt match a line's start
    while ( preg_match( $pattern, $data ) === 0 ){
    $byte--;
    $content->fseek($byte);
    $data = $content->current();
    }

//go backward 1 more position to start the next loop
    $byte--;
    $content->fseek($byte);
}

希望有一天能帮助某人xD

答案 2 :(得分:0)

这是一个老问题但是使用SplFileObj最简单的方法是使用密钥并寻求,

public function prev(){
    $key = $this->_splFileObj->key();
    if( $key ){
        --$key;
    }
    $this->_splFileObj->seek($key);
}

假设此方法位于SplFileObj的包装中,其属性为_splFileObj