我怎样才能最有效地读取 php 中大型文本文件的前 n 行?

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

提问人:Ryan 提问时间:5/11/2015 最后编辑:Ryan 更新时间:5/11/2015 访问量:1346

问:

到目前为止,我能够返回整个文件或空字符串。但不是预期的文件的第一行。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

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);

}
php fopen fgets fread feof

评论

0赞 fbas 5/11/2015
我看不出$buffer在哪里使用过。如果不需要,请将其删除。
0赞 Ryan 5/11/2015
对不起,在翻译中错过了。缓冲区加回。

答:

1赞 fbas 5/11/2015 #1

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

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

评论

0赞 Halayem Anis 5/11/2015
是的,它是!也许您的 TEXT 文件有编码问题?
0赞 Ryan 5/11/2015
这将打印出来 .我以为$line是每行的内容。我错过了什么?$lines打印出来1\n1\n...9\n8\n...
1赞 Halayem Anis 5/11/2015
我已经更新了我的回复:在测试相等性之前,你必须通过 fgets 影响$line,否则你会得到真/假......
0赞 Ryan 5/11/2015
这很好地解决了它!谢谢!