如何最有效地读取 php 中大型文本文件的前 n 行?

How can I most efficiently read the first n lines of a large text file in php?

到目前为止,我能够 return 整个文件或一个空字符串。但不是预期的文件的前 n 行。

echo head('/path/to/my_file.txt',100); // returns '', or in other versions `1\n1\n...`

function head($filepath, $lines = 1, $adaptive = true) {

    // Open file
    $f = @fopen($filepath, "rb");
    if ($f === false) return false;

    // Sets buffer size
    if (!$adaptive) $buffer = 4096;
    else $buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096));

    // Start reading
    $output = '';
    while($line = fgets($f,$buffer) !== false) {
        if (feof($f)) break;
        $output .= $line . "\n";
    }

    // Close file and return
    fclose($f);
    return trim($output);

}

相比之下,以下 tail 函数 (source) 可以完美运行:

function tail($filepath, $lines = 1, $adaptive = true) {

    // Open file
    $f = @fopen($filepath, "rb");
    if ($f === false) return false;

    // Sets buffer size
    if (!$adaptive) $buffer = 4096;
    else $buffer = ($lines < 2 ? 64 : ($lines < 10 ? 512 : 4096));

    // Jump to last character
    fseek($f, -1, SEEK_END);

    // Read it and adjust line number if necessary
    // (Otherwise the result would be wrong if file doesn't end with a blank line)
    if (fread($f, 1) != "\n") $lines -= 1;

    // Start reading
    $output = '';
    $chunk = '';

    // While we would like more
    while (ftell($f) > 0 && $lines >= 0) {

        // Figure out how far back we should jump
        $seek = min(ftell($f), $buffer);

        // Do the jump (backwards, relative to where we are)
        fseek($f, -$seek, SEEK_CUR);

        // Read a chunk and prepend it to our output
        $output = ($chunk = fread($f, $seek)) . $output;

        // Jump back to where we started reading
        fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR);

        // Decrease our line counter
        $lines -= substr_count($chunk, "\n");

    }

    // While we have too many lines
    // (Because of buffer size we might have read too many)
    while ($lines++ < 0) {

        // Find first newline and remove all text before that
        $output = substr($output, strpos($output, "\n") + 1);

    }

    // Close file and return
    fclose($f);
    return trim($output);

}

您只需要计算读取的行数,并在达到 $lines 后中止。

 $i = 0;
 while($line = fgets($file) !== false) {
        if (feof($file)) break;
        $output .= $line . "\n";
        if ($i++ >= $lines) {
          break;
        }
    }
// here the correction => apply parenthesis before ...
while(($line = fgets($f)) !== false) {
    if (feof($f)) break;
    if ($lines-- == 0) break;
    $output .= $line . "\n";
}