【问题标题】:PHP LimitIterator fails ("Does not support seeking" + "Cannot rewind file")PHP LimitIterator 失败(“不支持搜索”+“无法回退文件”)
【发布时间】:2012-07-03 18:47:57
【问题描述】:

我使用SplFileObjectLimitIterator 来读取一个大文件中从位置x 到y 的内容。

这在使用像/home/devel/stuff/myfile.log 这样的文件路径时非常有效。

当使用像http://mydomain.com:8090/devel/stuff/myfile.log 这样的路径时,它不起作用。但是路径是正确的。

使用绝对路径时会失败吗?


错误信息是:

PHP Warning: SplFileObject::rewind() [<a href='splfileobject.rewind'>splfileobject.rewind</a>]: stream does not support seeking in ...

PHP Fatal error: Uncaught exception 'RuntimeException' with message 'Cannot rewind file ...'


完整代码:

  // $pStrFile contains the valid (yes!) path
  $oFile = new SplFileObject($pStrFile);
  // $nFrom = 80 and $nLines = 30
  $fileIterator = new LimitIterator($oFile, $nFrom, $nLines);

  foreach($fileIterator as $line) {
      $strLines .= $line;
  }

【问题讨论】:

    标签: php spl splfileobject


    【解决方案1】:

    要让rewind() 函数在SplFileObject 上工作,底层流包装器需要支持查找。

    PHP 当前的HTTP stream wrapper 不支持查找。所以你得到错误信息:

    PHP 警告:SplFileObject::rewind() [splfileobject.rewind]:流不支持在...中查找

    我想到的第一个想法是使用 NoRewindIterator,它只是禁用 rewind() 调用,从而防止触发错误。

    $obj      = new SplFileObject('http://www.stackoverflow.com/');
    $norewind = new NoRewindIterator($obj);
    $limit    = new LimitIterator($norewind, 80, 30);
    

    但是,由于不再有rewind()LimitIterator 也有点被愚弄了。这导致忽略 offset 参数,它不会是 80 的偏移量,而只是零(无偏移量)。

    为了克服这个问题,可以将CachingIterator 插入到混音中。它正好解决了这个问题:

    $obj      = new SplFileObject('http://www.stackoverflow.com/');
    $norewind = new NoRewindIterator($obj);
    $caching  = new CachingIterator($norewind);
    $limit    = new LimitIterator($caching, 80, 30);
    
    foreach ($limit as $i => $line)
    {
        printf("%03d: %s", $i, $line);
     }
    

    示例输出 (Demo):

    080: 
    081: </span>
    082:                 </div>
    083:                 <div id="hsearch">
    084:                     <form id="search" action="/search" method="get" autocomplete="off">
    085:                     <div>
    

    如您所见,从技术上讲,PHP SPL 附带了足够多的内部工具,可以省去为 HTTP 流写入临时文件的时间。但请记住,这里的迭代器只能向前,也就是说你只能使用一次。

    【讨论】:

      【解决方案2】:

      这是 http 包装器的限制。如果文件在磁盘上,您可以在任何位置访问它。如果您想在文件中间开始阅读,这是可能的。但是,当文件位于网络服务器上并且您使用 HTTP 获取它时,读取文件中间会有点困难。

      你可以将copy文件放到一个临时位置,然后在上面使用LimitIterator。

      【讨论】:

      • 嗯,这不是我想要的,但它是目前有效的解决方案。谢谢。
      猜你喜欢
      • 1970-01-01
      • 2015-05-29
      • 1970-01-01
      • 2010-09-08
      • 1970-01-01
      • 2017-04-18
      • 1970-01-01
      • 2019-10-18
      • 1970-01-01
      相关资源
      最近更新 更多