关于php:如何逐行读取大文件?


How to read a large file line by line?

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

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

文件大小为1 GB。


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

1
2
3
4
5
6
7
8
9
10
$handle = fopen("inputfile.txt","r");
if ($handle) {
    while (($line = fgets($handle)) !== false) {
        // process the line read.
    }

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


1
2
3
4
5
6
7
if ($file = fopen("file.txt","r")) {
    while(!feof($file)) {
        $line = fgets($file);
        # do same stuff with the $line
   }
    fclose($file);
}


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

1
2
3
4
5
6
7
8
9
10
11
12
<?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;


如果您要打开一个大文件,您可能希望使用生成器和fgets()来避免将整个文件加载到内存中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * @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);
};

像这样使用它:

1
2
3
foreach ($fileData() as $line) {
    // $line contains current line
}

这样您就可以在foreach()中处理单个文件行。

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


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

1
2
3
4
5
6
7
$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);
    ///
}


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

1
2
3
4
foreach(file('myfile.txt') as $line) {
   echo $line."
"
;
}


1
2
3
foreach (new SplFileObject(__FILE__) as $line) {
    echo $line;
}


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

1
2
3
4
5
6
7
$fp=fopen("/path/to/the/file","r+");
while ($line = stream_get_line($fp, 1024 * 1024,"
"
))
{
echo $line;
}
fclose($fp);


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


这个问题的流行解决方案之一将涉及新线字符的问题。使用简单的str_replace可以很容易地修复它。

1
2
3
4
5
6
7
8
$handle = fopen("some_file.txt","r");
if ($handle) {
    while (($line = fgets($handle)) !== false) {
        $line = str_replace("
"
,"", $line);
    }
    fclose($handle);
}

这是我如何处理非常大的文件(测试高达100G)。它比fgets()快

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$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("
"
,$temp);
       $fgetslines[0]=$left.$fgetslines[0];
       if(!feof($fh) )$left = array_pop($lines);          
       foreach ($fgetslines as $k => $line) {
           //do smth with $line
        }
     }
}
fclose($fh);


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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) .'';$k++;
        $contents .= fgets($fp);
    }
    echo '';
    file_put_contents('Split/new_file_'.$f.'.txt', $contents);$f++;
}
?>

函数读取数组返回

1
2
3
4
5
6
7
8
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;
}