如何逐行读取一个大文件?

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

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

文件大小为1gb。

801750 次浏览

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

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


fclose($handle);
}
if ($file = fopen("file.txt", "r")) {
while(!feof($file)) {
$line = fgets($file);
# do same stuff with the $line
}
fclose($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);
///
}

小心使用'while(!feof……Fgets()的东西,Fgets可以得到一个错误(返回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 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;

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

foreach(file('myfile.txt') as $line) {
echo $line. "\n";
}

对于这个问题,一个流行的解决方案是使用新的行字符。使用简单的str_replace就可以很容易地解决这个问题。

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

如果你想在打开一个大文件时使用foreach而不是while,你可能想在Generator中封装while循环,以避免将整个文件加载到内存中:

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


if (!$file) {
return; // die() is a bad practice, better to use return
}
while (($line = fgets($file)) !== false) {
yield $line;
}


fclose($file);
};

像这样使用它:

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

通过这种方式,您可以在foreach()中处理单个文件行。

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

这就是我如何处理非常大的文件(测试高达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);

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);
<?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++;
}
?>