【问题标题】:How do I open a file from line X to line Y in PHP?如何在 PHP 中打开从 X 行到 Y 行的文件?
【发布时间】:2011-02-18 00:16:21
【问题描述】:

我在 PHP 文档中看到的最接近的方法是 fread() 给定长度,但这并没有指定从哪一行开始。还有其他建议吗?

【问题讨论】:

    标签: php fopen


    【解决方案1】:

    是的,您可以使用SplFileObject::seek轻松做到这一点

    $file = new SplFileObject('filename.txt');
    $file->seek(1000);
    for($i = 0; !$file->eof() && $i < 1000; $i++) {
        echo $file->current(); 
        $file->next();
    }
    

    这是来自SeekableIterator 接口的方法,不要与fseek 混淆。

    由于 SplFileObject 是可迭代的,您可以使用 LimitIterator 更轻松地完成它:

    $file = new SplFileObject('longFile.txt');
    $fileIterator = new LimitIterator($file, 1000, 2000);
    foreach($fileIterator as $line) {
        echo $line, PHP_EOL;
    }
    

    同样,这是从零开始的,所以它是第 1001 到 2001 行。

    【讨论】:

    • +1 SPL 非常好,可以使用更多广告(和文档)
    • 请记住,SPL 实现的实现方式与第一个建议的解决方案相同。它将从第一个字节开始读取文件,一次一行,并将文件指针留在所需的行。没有办法解决这个问题。
    【解决方案2】:

    您将无法从第 X 行开始阅读,因为行可以是任意长度。因此,您必须从一开始就读取读取的行数才能到达第 X 行。例如:

    <?php
    $f = fopen('sample.txt', 'r');
    $lineNo = 0;
    $startLine = 3;
    $endLine = 6;
    while ($line = fgets($f)) {
        $lineNo++;
        if ($lineNo >= $startLine) {
            echo $line;
        }
        if ($lineNo == $endLine) {
            break;
        }
    }
    fclose($f);
    

    【讨论】:

    • 或者你可以只使用 file() 和 array_slice(),就像我的回答一样:)
    • 是的,除了读取整个文件。此代码仅读取所需的最小值。
    • 即使文件如此之大,我目前需要处理的文件是 25MB,它还能工作吗?
    • @lock,是的,应该。我给出的例子在内存中只有一行。只要没有太多,您就可以将这些行存储到一个数组中。话虽如此,与我必须处理的一些日志文件相比,25Mb 并不是很大。
    • 如果您在长时间运行的脚本和较低版本的 PHP 中遇到内存问题,最好尽可能避免使用对象,这就是为什么我更喜欢@grom 的答案
    【解决方案3】:

    不幸的是,为了能够从第 x 行读取到第 y 行,您需要能够检测换行符......并且您必须扫描整个文件。但是,假设您出于性能原因询问此问题,您可以使用以下内容获取 xy 行:

    $x = 10; //inclusive start line
    $y = 20; //inclusive end line
    $lines = file('myfile.txt');
    $my_important_lines = array_slice($lines, $x, $y);
    

    见:array_slice

    【讨论】:

    • 你应该注意数组以0开头,行号通常以1开头。所以应该有一个$x-1,$y-1或者记住$x=10真的是 $x=11.
    【解决方案4】:

    Here is the possible solution :)

    <?php
    $f = fopen('sample.txt', 'r');
    $lineNo = 0;
    $startLine = 3;
    $endLine = 6;
    while ($line = fgets($f)) {
        $lineNo++;
        if ($lineNo >= $startLine) {
            echo $line;
        }
        if ($lineNo == $endLine) {
            break;
        }
    }
    fclose($f);
    ?>
    

    【讨论】:

    • 但是它读取X之前的所有行。问题是问这部分是否可以跳过,不是吗?
    • 查看$startLine$endLine 变量,它只会读取这些行。
    • 问题不在于只处理给定的行 (>=startLine &&
    • 这是一个不错的解决方案,但仍然很耗时。您进入文件的深度越深,所需的时间就越长……而且我打算处理超过 10,000 行的文件。
    • @thedp:让我们看看是否有更好的解决方案:)
    【解决方案5】:

    好吧,你不能使用函数 fseek 来寻找合适的位置,因为它适用于给定的字节数。

    我认为没有某种缓存或逐行遍历是不可能的。

    【讨论】:

    • 行缓存呢?将每行的字节位置存储在某处,然后使用 fseek() 获取它们。
    • @christian studer:你说的是索引文件?如果文件是静态的并且大部分时间不会更改,这可能是一个有趣的解决方案。不幸的是,我要阅读的文件是仍在开发中的源代码文件,所以索引是不可能的。
    • 是的,索引它并缓存索引。 (文件上的时间戳可能会指示缓存的索引是否仍然有效)。 PHP 对于这些任务的速度惊人地快,如果您在同一个文件再次更改之前对它有多个请求,那么它的速度可能足够快。
    【解决方案6】:

    如果您要查找行,则不能使用 fread,因为它依赖于字节偏移量,而不是换行符的数量。实际上,您必须阅读文件才能找到换行符,因此使用不同的函数更合适。 fgets 将逐行读取文件。将其放入循环中并仅捕获您想要的行。

    【讨论】:

      【解决方案7】:

      我很害怕...我猜那是 B 计划:S

      对于每个 AJAX 请求,我将:

      1. 将我要返回给客户端的行数读入一个字符串。
      2. 将文件的其余部分复制到临时文件中。
      3. 将字符串返回给客户端。

      这很糟糕,如果有 10,000 多行文件,它可能会很慢,但我想这比一遍又一遍地阅读要好,至少每次请求都会使临时文件变短...不是吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-12
        • 2014-09-11
        • 1970-01-01
        • 1970-01-01
        • 2010-09-17
        相关资源
        最近更新 更多