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