【问题标题】:fseek() by line, not bytes?fseek() 逐行,而不是字节?
【发布时间】:2010-08-27 22:35:22
【问题描述】:

我有一个脚本可以逐行解析大文件。当遇到无法处理的错误时,它会停下来,通知我们最后一行已解析。

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

<?php

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

我使用它没有问题,它足够快 - 只是感觉有点脏。根据我对底层代码的了解,我认为没有更好的方法来做到这一点。

【问题讨论】:

    标签: php file fgets


    【解决方案1】:

    查找文件中特定行的一种简单方法是使用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 代码除外)。

    【讨论】:

    • 不错!不久前遇到这个并开始使用它。
    • 在这种情况下,seek 将直接读取第 10,000 行,而不是通过第 1 - 9,999 行到达给定行?
    • @Ali:不,你认为它是如何知道这些行从哪里开始的?它通读文件。如果您确实想直接查找一行,还有其他选择,但它们涉及潜在的复杂系统来跟踪文件中行的开始位置。
    • 你能给我一些点击吗?我搜索了很多以找到一种实用的方法来读取一行而不读取整个文件(考虑 GB 大小的大文件)。
    • @Ali:如果我没记错的话,这里有一个关于 SO 的问题,其中包含一个实现的细节,或者我可以分享我自己的细节(尽管 cmets 没有提供足够的空间)。抱歉,我没有(我认为我)看到的问题的链接。
    【解决方案2】:

    如果您只有行号可以继续,则没有其他方法可以找到该行。文件不是基于行的(甚至不是基于字符的),因此无法简单地跳转到文件中的特定行。

    可能还有其他读取文件行的​​方法可能会稍快一些,例如将较大的文件块读取到缓冲区中并从中读取行,但您只能希望它快几个百分点.任何在文件中查找特定行的方法仍然需要读取该行之前的所有数据。

    【讨论】:

    • 是的,我也这么认为。不知何故,我认为一个很好的 fseekbyline() 只是 C 代码的包装器会让我感觉更好。呵呵。
    【解决方案3】:

    我知道发帖迟了,但它可以帮助一些人 有一天我做了一个像 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);
    }
    

    没有错误系统,如果你想转到

    如果你想离开eot也一样

    【讨论】:

    • 当 PHP 完成 for 循环时,指针将位于您想要的位置。只需调用 fgets($handle) 就足以放入 for 循环,并且可以避免在 $bufcarac 和 $ligne 变量中加载内存。
    【解决方案4】:
    rewind($handle);
    
    for ($i=0; $i < $desired_line; $i++) {
        fgetcsv($handle, 1000, ",");
    }
    

    当我需要在脚本中多次倒退到特定行时,这对我有用。

    我不确定这是否会消耗内存或速度,但它可以解决问题。

    【讨论】:

    • 这很简短。虽然 fgetcsv 特定于 CSV 文件而不是任何文本文件。至少对我有帮助。
    【解决方案5】:

    如果我理解正确,您想在发现错误后的某个时间点查找特定行。如果是这种情况,您可能会在某处存储或打印坏行的行号,具体取决于“通知”的含义。

    除非你真的意味着你不能使用fseek()*,你可以做的是也存储/打印文件中坏行开始的位置。然后你可以fseek()

    * 在这种情况下,fseekbyline() 如果存在,它如何可用?

    【讨论】:

      猜你喜欢
      • 2013-12-17
      • 2020-08-12
      • 2021-02-19
      • 1970-01-01
      • 1970-01-01
      • 2012-10-20
      • 1970-01-01
      • 2018-12-07
      • 1970-01-01
      相关资源
      最近更新 更多