540

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

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

文件大小为 1 GB。

4

14 回答 14

781

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

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

    fclose($handle);
} else {
    // error opening the file.
} 
于 2012-11-06T07:51:30.540 回答
137
if ($file = fopen("file.txt", "r")) {
    while(!feof($file)) {
        $line = fgets($file);
        # do same stuff with the $line
    }
    fclose($file);
}
于 2012-11-06T07:55:24.480 回答
117

您可以为文件使用面向对象的接口类 - SplFileObject http://php.net/manual/en/splfileobject.fgets.php (PHP 5 >= 5.1.0)

<?php

$file = new SplFileObject("file.txt");

// Loop until we reach the end of the file.
while (!$file->eof()) {
    // Echo one line from the file.
    echo $file->fgets();
}

// Unset the file to call __destruct(), closing the file handle.
$file = null;
于 2014-10-04T05:28:56.383 回答
80

如果您要打开一个大文件,您可能希望在 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() 中处理单个文件行。

注意:生成器需要 >= PHP 5.5

于 2017-03-27T17:54:37.787 回答
35

有一个file()函数可以返回文件中包含的行数组。

foreach(file('myfile.txt') as $line) {
   echo $line. "\n";
}
于 2015-04-09T07:06:25.493 回答
31

使用缓冲技术来读取文件。

$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);
    ///
}
于 2012-11-06T08:23:30.883 回答
30

显而易见的答案并不存在于所有回复中。
PHP 有一个简洁的流定界符解析器可用于此目的。

$fp = fopen("/path/to/the/file", "r");
while (($line = stream_get_line($fp, 1024 * 1024, "\n")) !== false) {
  echo $line;
}
fclose($fp);
于 2018-06-21T20:46:23.060 回答
25
foreach (new SplFileObject(__FILE__) as $line) {
    echo $line;
}
于 2015-11-25T00:21:21.183 回答
9

这就是我管理非常大文件的方式(测试高达 100G)。它比 fgets() 更快

$block =1024*1024;//1MB or counld be any higher than HDD block_size*2
if ($fh = fopen("file.txt", "r")) { 
    $left='';
    while (!feof($fh)) {// read the file
       $temp = fread($fh, $block);  
       $fgetslines = explode("\n",$temp);
       $fgetslines[0]=$left.$fgetslines[0];
       if(!feof($fh) )$left = array_pop($lines);           
       foreach ($fgetslines as $k => $line) {
           //do smth with $line
        }
     }
}
fclose($fh);
于 2017-08-04T13:24:58.087 回答
8

小心'while(!feof ... fgets()'的东西,fgets可能会出错(返回false)并永远循环而不会到达文件末尾。codaddict最接近正确但是当你的'while fgets'循环结束,检查 feof;如果不是真的,那么你有一个错误。

于 2014-01-28T21:14:06.160 回答
8

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;
}
于 2018-02-24T15:43:19.857 回答
7

这个问题的流行解决方案之一将与新行字符有关。它可以很容易地用一个简单的str_replace.

$handle = fopen("some_file.txt", "r");
if ($handle) {
    while (($line = fgets($handle)) !== false) {
        $line = str_replace("\n", "", $line);
    }
    fclose($handle);
}
于 2015-07-19T01:18:15.563 回答
2
<?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++;
}
?>
于 2019-06-23T15:07:23.253 回答
-9

带数组返回的读取函数

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;
}
于 2014-03-17T16:19:15.453 回答