Php 如何逐行读取大型文件?

Php 如何逐行读取大型文件?,php,Php,我想逐行读取文件,但不想将其完全加载到内存中 我的文件太大,无法在内存中打开,如果尝试这样做,我总是会出现内存不足错误 文件大小为1 GB。您可以使用fgets()函数逐行读取文件: $handle = fopen("inputfile.txt", "r"); if ($handle) { while (($line = fgets($handle)) !== false) { // process the line read. } fclose($ha

我想逐行读取文件,但不想将其完全加载到内存中

我的文件太大,无法在内存中打开,如果尝试这样做,我总是会出现内存不足错误


文件大小为1 GB。

您可以使用
fgets()
函数逐行读取文件:

$handle = fopen("inputfile.txt", "r");
if ($handle) {
    while (($line = fgets($handle)) !== false) {
        // process the line read.
    }

    fclose($handle);
} else {
    // error opening the file.
} 

使用缓冲技术读取文件

$filename = "test.txt";
$source_file = fopen( $filename, "r" ) or die("Couldn't open $filename");
while (!feof($source_file)) {
    $buffer = fread($source_file, 4096);  // use a buffer of 4KB
    $buffer = str_replace($old,$new,$buffer);
    ///
}
foreach(file('myfile.txt') as $line) {
   echo $line. "\n";
}

小心“while(!feof…fgets()”之类的东西,fgets可能会出现错误(returnfing false)并在不到达文件结尾的情况下永远循环。codaddict最接近于正确,但当“while fgets”循环结束时,请检查feof;如果不是真的,则表示您有错误。

使用数组返回读取的函数

function read_file($filename = ''){
    $buffer = array();
    $source_file = fopen( $filename, "r" ) or die("Couldn't open $filename");
    while (!feof($source_file)) {
        $buffer[] = fread($source_file, 4096);  // use a buffer of 4KB
    }
    return $buffer;
}

您可以对文件使用面向对象的接口类-SplFileObject(PHP5>=5.1.0)

有一个
file()
函数,它返回文件中包含的行数组

$filename = "test.txt";
$source_file = fopen( $filename, "r" ) or die("Couldn't open $filename");
while (!feof($source_file)) {
    $buffer = fread($source_file, 4096);  // use a buffer of 4KB
    $buffer = str_replace($old,$new,$buffer);
    ///
}
foreach(file('myfile.txt') as $line) {
   echo $line. "\n";
}

这个问题的一个流行解决方案是新行字符的问题。用一个简单的
str\u替换
就可以很容易地解决这个问题

$handle = fopen("some_file.txt", "r");
if ($handle) {
    while (($line = fgets($handle)) !== false) {
        $line = str_replace("\n", "", $line);
    }
    fclose($handle);
}

如果要打开一个大文件,可能需要在fgets()旁边使用生成器,以避免将整个文件加载到内存中:

/**
 * @return Generator
 */
$fileData = function() {
    $file = fopen(__DIR__ . '/file.txt', 'r');

    if (!$file)
        die('file does not exist or cannot be opened');

    while (($line = fgets($file)) !== false) {
        yield $line;
    }

    fclose($file);
};
像这样使用它:

foreach ($fileData() as $line) {
    // $line contains current line
}
这样,您就可以在foreach()中处理单个文件行


注意:生成器需要>=PHP5.5

这是我如何管理非常大的文件(使用高达100G的文件进行测试)的。而且它比fgets()更快


SplFileObject在处理大型文件时非常有用

function parse_file($filename)
{
    try {
        $file = new SplFileObject($filename);
    } catch (LogicException $exception) {
        die('SplFileObject : '.$exception->getMessage());
    }
    while ($file->valid()) {
        $line = $file->fgets();
        //do something with $line
    }

    //don't forget to free the file handle.
    $file = null;
}

所有的回答中都没有明显的答案。
PHP有一个整洁的流分隔符解析器,可用于此目的

$fp = fopen("/path/to/the/file", "r+");
while (($line = stream_get_line($fp, 1024 * 1024, "\n")) !== false) {
  echo $line;
}
fclose($fp);


看看我的答案,你应该使用
fgets()
不带
$length
参数。是否将以下任何一项标记为答案?这是如何解释
太大而无法在内存中打开的部分的?您没有在内存中读取整个文件。运行此操作所需的最大内存取决于输入中最长的行。@Brandin-Moot-在这些情况下,asked问题,即逐行读取文件,没有明确定义的结果。@ToolmakerSteve然后定义应该发生什么。如果需要,可以打印消息“行太长;放弃”这也是一个定义良好的结果。行是否可以包含布尔值false?如果是,则此方法将停止,而不会到达文件结尾。此URL上的示例#1表明,即使尚未到达文件结尾,fgets有时也可以返回布尔值false。在该页面的注释部分,人们报告fgets()并不总是返回正确的值,因此使用feof作为循环条件更安全。1 GB的文件将全部读入内存并转换为1 GB以上的数组…祝你好运。这不是问题的答案,但它确实回答了许多人在这里看到的更常见的问题,因此它仍然很有用,谢谢。file()对于处理小文件非常方便。尤其是当您希望数组()作为最终结果时。对于较大的文件来说,这是一个坏主意,因为整个文件一次读取到一个数组。这在大文件上会严重中断,因此正是该方法不起作用。这将在内存中创建一个超过1 GB的数组(祝你好运)甚至不分行,而是分为任意4096个字符的块。你到底为什么要这样做?正如@Cuse70在他的回答中所说,如果文件不存在或无法打开,这将导致无限循环。在while循环之前测试
if($file)
,我知道这很旧,但是:使用while(!feof($file))不建议使用。顺便说一句:“如果文件指针中没有更多数据可读取,则返回FALSE。”…以防万一
feof()
不再存在?更干净的解决方案。谢谢;)还没有使用过这个类,这里有更多有趣的函数需要探索:谢谢。是的,例如,你可以在$file->setFlags(SplFileObject::DROP_NEW_line)之前添加这一行,以便在一行的末尾删除新行。据我所知,没有
eof()
SplFileObject中的函数?谢谢!另外,请使用
rtrim($file->fgets())
如果您不需要,可以为每个读取的行字符串去除尾随的换行符。@Chud37是的,有:这值得更多的喜爱,因为它可以处理大文件,甚至是没有回车符或非常长的行的文件……如果OP真的不关心实际的行,只是想提供一个服务,我不会感到惊讶在这种情况下,这个答案很好(大多数PHP程序员都会这么做)顺便说一句?假设我们需要指定打开的url!这应该是一个可以接受的答案。生成器的速度快了一百倍。而且内存效率也更高。@NinoŠkopac:你能解释一下为什么这个解决方案内存效率更高吗?例如,与
SplFileObject
方法相比。不确定Tachi和Onin的评论与之比较,但我将其与90MB的文本文件进行了比较,与codadict的方法相比,发现速度慢了44%,并且使用了相同的内存量。(在PHP7.3上运行)如何确保1024×1024块在中间行不中断?@ USE151496容易!!计数…1.2.3。4@OmarElDon什么意思?与
file()
相比,内存效率更高。
function parse_file($filename)
{
    try {
        $file = new SplFileObject($filename);
    } catch (LogicException $exception) {
        die('SplFileObject : '.$exception->getMessage());
    }
    while ($file->valid()) {
        $line = $file->fgets();
        //do something with $line
    }

    //don't forget to free the file handle.
    $file = null;
}
$fp = fopen("/path/to/the/file", "r+");
while (($line = stream_get_line($fp, 1024 * 1024, "\n")) !== false) {
  echo $line;
}
fclose($fp);
<?php
echo '<meta charset="utf-8">';

$k= 1;
$f= 1;
$fp = fopen("texttranslate.txt", "r");
while(!feof($fp)) {
    $contents = '';
    for($i=1;$i<=1500;$i++){
        echo $k.' -- '. fgets($fp) .'<br>';$k++;
        $contents .= fgets($fp);
    }
    echo '<hr>';
    file_put_contents('Split/new_file_'.$f.'.txt', $contents);$f++;
}
?>