如何在不受内存限制的情况下在php中读取大文件

时间:2019-04-01 14:09:07

标签: php file memory-limit

我正在尝试逐行读取文件。问题是文件太大(超过500000行),我超出了内存限制。我想知道如何在不受内存限制的情况下读取文件。

我正在考虑多线程的解决方案(例如将文件分成较小的组(每组100000行)并在多线程中读取它),但是我不知道如何进行详细处理。请帮助我(对不起,英语不好。)

这是我的代码

$fn = fopen("myfile.txt", "r");

while(!feof($fn)) {
    $result = fgets($fn);
    echo $result;
}

fclose($fn);

4 个答案:

答案 0 :(得分:4)

您可以使用generator来处理内存使用情况。这只是用户在文档页面上写的一个示例:

function getLines($file)
{
    $f = fopen($file, 'r');

    try {
        while ($line = fgets($f)) {
            yield $line;
        }
    } finally {
        fclose($f);
    }
}

foreach (getLines("file.txt") as $n => $line) {
    // insert the line into db or do whatever you want with it.
}
  

生成器允许您编写代码,该代码使用foreach遍历一组数据,而无需在内存中构建数组,这可能会导致您超出内存限制,或需要大量的处理时间才能生成。取而代之的是,您可以编写一个生成器函数,该函数与普通函数相同,不同之处在于,生成器可以返回所需的多次次数,而不是返回一次,以提供要迭代的值。

答案 1 :(得分:1)

根据我的经验,清除作用域后,PHP可以最好地清除内存。循环不算作范围,而函数算作范围。
因此,将文件指针移至某个函数,在该函数中执行数据库操作,然后退出该函数循环,可以在其中调用gc_collect_cycles()可以帮助管理内存并强制php自行清理。

我还建议关闭回显,而是登录到文件。然后,您可以使用命令tail -f filename读取该日志输出(Windows linux子系统,用于Windows bash的git或在linux上)

我使用与下面类似的方法来处理具有数百万个条目的大型文件,这有助于保持在内存限制之下。

function dostuff($fn) 
{
    $result = fgets($fn);
    // store database, do transforms, whatever
    echo $result;
}

$fn = fopen("myfile.txt", "r");

while(!feof($fn)) {
    dostuff($fn);
    flush(); // only need this if you do the echo thing.
    gc_collect_cycles();
}

fclose($fn);

答案 2 :(得分:1)

您可以使用readfileob_get_level来管理内存和输出缓冲。

  

readfile()本身不会出现任何内存问题,即使在发送大文件时也是如此。如果遇到内存不足错误,请确保使用ob_get_level()关闭输出缓冲。

在执行读取时,您可能仍然使PHP输出缓冲处于活动状态。

使用以下方法进行确认:

  

您可以在脚本开始时使用以下命令停止输出缓冲(如果已经开始的话):

if (ob_get_level()) {
  ob_end_clean();
}

答案 3 :(得分:-1)

您可以像ini_set('memory_limit',-1)那样设置内存限制; //您的脚本在完成读取之前不会停止。但这是错误的方式,因为它占用了服务器的CPU使用时间。

更好的方法是将文件分成几块,

将文件数据隐藏到数组中,然后可以轻松地像大块一样读取数据

$file_lines = file('mytext.txt');
foreach ($file_lines as $line) {
    echo $line;
}

$ file_lines是您的数组。