按行而非字节进行fseek()定位?

18

我有一个逐行解析大文件的脚本。当它遇到无法处理的错误时,会停止并通知我们最后一行被解析的位置。

这真的是寻找文件中特定行的最佳/唯一方法吗?(fseek() 在我的情况下无法使用。)

<?php

for ($i = 0; $i < 100000; $i++)
    fgets($fp); // just discard this

我使用这个没有问题,速度也足够快 - 只是感觉有点不好。根据我对底层代码的了解,我想象不出有更好的方法来做到这一点。

5个回答

37
使用SplFileObject类可以轻松地在文件中定位到指定行,该类支持按行号(seek())或字节偏移量(fseek())进行定位。
$file = new SplFileObject('myfile.txt');
$file->seek(9999);     // Seek to line no. 10,000
echo $file->current(); // Print contents of that line

在后台,seek()只是执行了您的PHP代码所做的事情(除了以C代码形式)。

不错!之前遇到过这个东西并开始使用它。 - jasonbar
在这种情况下,查找操作将直接读取第10,000行,而不是遍历1到9,999行来达到指定的行。 - Googlebot
@Ali:不,你认为它是怎么知道行的起始位置的?它会逐行读取文件。如果你确实想要直接跳转到某一行,还有其他选择,但这可能涉及到复杂的系统来跟踪文件中每行的起始位置。 - salathe
请问您能给我一些提示吗?我搜索了很多,想找到一种实用的方法,在不读取整个文件的情况下读取一行(考虑到GB级别的大文件)。 - Googlebot
在处理大文件时似乎存在一个错误,在某个数量级别之后,搜索操作将停留在同一行上,并且如果与while->eol一起使用,则会创建无限循环。 - Tofandel
显示剩余2条评论

5
如果你只有行号,没有其他方法找到这一行。文件不是基于行(甚至不是基于字符)的,所以没有办法在文件中简单地跳转到特定的行。
可能有其他读取文件行的方式会稍微快一点,比如将大块文件读入缓存并从中读取行,但你只能希望它会快几个百分点。任何在文件中查找特定行的方法仍然必须读取该行之前的所有数据。

是的,我也想到了。不知怎么的,我以为一个很好的 fseekbyline() 只是 C 代码的包装器会让我感觉更好。哈哈。 - jasonbar

4

我知道现在发帖可能有些晚了,但它可以帮助一些人。 有一天,我写了一个类似于fseekbyline的函数...

function GoToLine($handle,$line)
{
  fseek($handle,0);  // seek to 0
  $i = 0;
  $bufcarac = 0;                    

  for($i = 1;$i<$line;$i++)
  {
    $ligne = fgets($handle);
    $bufcarac += strlen($ligne);  // in the end bufcarac will contains all caracters until the line
  }  

  fseek($handle,$bufcarac);
}

没有错误系统,如果你想要跳转到第1行或203行但文件为空......那么你将得到没有意义的内容。

同样地,如果你想要跳出eot,也会面临类似的问题。


1
当 PHP 完成 for 循环后,指针将位于您所期望的位置。只需要调用 fgets($handle) 就足以放入 for 循环中,这样您就可以避免在 $bufcarac 和 $ligne 变量中加载内存。 - Gregory

1
rewind($handle);

for ($i=0; $i < $desired_line; $i++) {
    fgetcsv($handle, 1000, ",");
}

这对我很有帮助,因为我需要在我的脚本中多次倒回到特定的行。我不确定这是否会消耗内存或速度,但它能解决问题。

这段内容简短明了。虽然fgetcsv函数只适用于CSV文件而非其他文本文件,但对我来说还是很有帮助的。 - Gregory

0

如果我理解正确,您想在找到错误后的某个时间点寻找特定行。如果是这样,您可能会在某个地方存储或打印错误行的行号,具体取决于您所说的“通知”是什么意思。

除非您真的不能使用 fseek()*,否则您可以存储/打印坏行开始的文件位置。然后您就可以使用 fseek()

* 如果存在 fseekbyline(),那么在这种情况下,该函数如何可用?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接