所以我正在为自己做一个小实验,一个读取php错误日志文件(使用SplFileObject(并在浏览器上输出格式化的脚本。
我认为以相反的顺序显示它会更合乎逻辑(顶部的最新错误(。要使用"正常"顺序,我只需要显示每一行并调用$file->next((;移动指针,但由于我正在以另一种方式进行操作,而且据我所知,还没有prev()
或previous()
方法,我找到的唯一方法是使用seek()
:
for($i = $lines_total - $start_at; $i > $lines_total - $start_at - $lines_to_get; $i--){
$content->seek($i);
$data = $content->current();
if(empty($data)){
continue;
}
}
但这非常慢(对于一个16mb的文件,大约7秒(。如果我按照正常的顺序做,那就是即时的。
有人知道什么方法吗?或者我想做的是疯狂的?xD我只是一个被迫编写代码的设计师,所以我不太熟悉指针之类的东西。
来自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();
}
}
如果将来有人遇到这个问题,我会想出一个非常简单的解决方案:
//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
这是一个老问题,但对于SplFileObj,最简单的方法是使用密钥和查找,
public function prev(){
$key = $this->_splFileObj->key();
if( $key ){
--$key;
}
$this->_splFileObj->seek($key);
}
假设此方法位于属性为_splFileObj
的SplFileObj的包装器中。