如何从大型(4GB +)打开文件中读取新添加的行?

时间:2019-04-04 03:39:19

标签: php

使用PHP 7.3,我试图实现“ tail -f”功能:打开文件,等待其他过程写入该文件,然后读取这些新行。

不幸的是,似乎fgets()缓存了EOF条件。即使有新数据可用(filemtime更改),fgets()也会返回空白行。

重要的部分:我不能简单地关闭,重新打开然后寻找,因为文件大小为数十演出,远高于32位限制。文件必须保持打开状态才能能够从正确的位置读取新数据。

我已经附加了一些代码来演示该问题。如果将数据追加到输入文件中,则filemtime()会检测到更改,但是fgets()不会读取任何新内容。

fread() 似乎可行,可以获取新数据,但我宁愿不必自己动手编写“读取一行”解决方案。

有人知道我怎么可以戳fgets()意识到它不是EOF吗?

$fn = $argv[1];

$fp = fopen($fn, "r");
fseek($fp, -1000, SEEK_END);
$filemtime = 0;
while (1) {
  if (feof($fp)) {
    echo "got EOF\n";
    sleep(1);
    clearstatcache();
    $tmp = filemtime($fn);
    if ($tmp != $filemtime) {
      echo "time $filemtime -> $tmp\n";
      $filemtime = $tmp;
    }
  }
  $l = trim(fgets($fp, 8192));
  echo "l=$l\n";
}

更新:我尝试排除对feof的调用(认为可能是状态被缓存的地方),但是行为没有改变;一旦fgets到达原始文件指针位置,即使随后附加了更多数据,任何进一步的fgets读取都将返回false。


更新2:我最终滚动了自己的函数,该函数将在到达第一个EOF之后继续返回新数据(实际上,它没有EOF的概念,只是可用数据/不可用数据)。代码未经严格测试,使用风险自负。希望这对其他人有帮助。

define('FGETS_TAIL_CHUNK_SIZE', 4096);
define('FGETS_TAIL_SANITY', 65536);
define('FGETS_TAIL_LINE_SEPARATOR', 10);

function fgets_tail($fp) {

// Get complete line from open file which may have additional data written to it.
// Returns string (including line separator) or FALSE if there is no line available (buffer does not have complete line, or is empty because of EOF)

  global $fgets_tail_buf;

  if (!isset($fgets_tail_buf))  $fgets_tail_buf = "";

  if (strlen($fgets_tail_buf) < FGETS_TAIL_CHUNK_SIZE) { // buffer not full, attempt to append data to it
    $t = fread($fp, FGETS_TAIL_CHUNK_SIZE);
    if ($t != false)  $fgets_tail_buf .= $t;
  }
  $ptr = strpos($fgets_tail_buf, chr(FGETS_TAIL_LINE_SEPARATOR));
  if ($ptr !== false) {
    $rv = substr($fgets_tail_buf, 0, $ptr);                 // includes line separator
    $fgets_tail_buf = substr($fgets_tail_buf, $ptr + 1);    // may reduce buffer to empty
    return($rv);
  } else {
    if (strlen($fgets_tail_buf) < FGETS_TAIL_SANITY) { // line separator not found, try to append some more data
      $t = fread($fp, FGETS_TAIL_CHUNK_SIZE);
      if ($t != false)  $fgets_tail_buf .= $t;
    }
  }
  return(false);
}

0 个答案:

没有答案