How to read a large file line by line?
我想逐行读取文件,但没有完全加载到内存中。
我的文件太大而无法在内存中打开,如果尝试这样做,我总是会出现内存错误。
文件大小为1 GB。
-
在这个链接上看到我的答案
-
您应该使用fgets()而不使用$length参数。
-
您想在以下任何一项上标记答案吗?
您可以使用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.
} |
-
这如何解释too large to open in memory部分?
-
您没有在内存中读取整个文件。运行此操作所需的最大内存取决于输入中的最长行。
-
当然还记得fclose($handle);;)
-
有关在上传文件时读取文件的方法,请尝试如何在PHP中上传.txt文件并在另一页上逐行读取文件?
-
@Brandin - Moot - 在这些情况下,提问题,即读取LINE BY LINE文件,没有明确定义的结果。
-
@ToolmakerSteve然后定义应该发生的事情。如果你想要,你只需打印"行太长;放弃"的信息。这也是一个定义明确的结果。
-
一行可以包含布尔值false吗?如果是这样,那么此方法将在不到达文件末尾的情况下停止。此URL上的示例#1 php.net/manual/en/function.fgets.php表明,即使尚未到达文件末尾,fgets有时也会返回布尔值false。在该页面的评论部分,人们报告fgets()并不总是返回正确的值,因此使用feof作为循环条件更安全。
-
只是不设置缓冲区,它将逐行读取
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);
} |
-
正如@ Cuse70在他的回答中所说,如果文件不存在或无法打开,这将导致无限循环。在while循环之前测试if($file)
-
我知道这是旧的,但是:不推荐使用while(!feof($ file))。看看这里。
-
BTW:"如果文件指针中没有更多要读取的数据,则返回FALSE。" php.net/manual/en/function.fgets.php ...以防万一
-
feof()不再存在?
您可以为文件使用面向对象的接口类 - 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; |
-
更清洁的解决方案谢谢;)还没有使用过这个类,这里??有更多有趣的函数可以探索:php.net/manual/en/class.splfileobject.php
-
谢谢。是的,例如你可以在$ file-> setFlags(SplFileObject :: DROP_NEW_LINE)之前添加这一行;为了在一行末尾删除换行符。
-
据我所知,SplFileObject中没有eof()函数?
-
这是:php.net/manual/en/splfileobject.eof.php
-
谢谢!此外,如果您不想要它们,请使用rtrim($file->fgets())去除每个读取的行字符串的尾随换行符。
如果您要打开一个大文件,您可能希望使用生成器和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);
///
} |
-
这值得更多的爱,因为它将适用于大型文件,甚至没有回车或超长行的文件......
-
如果OP并不真正关心实际线路并且仅仅想要例如,我不会感到惊讶。提供下载服务。在这种情况下,这个答案很好(大多数PHP程序员都会这么做)。
有一个file()函数返回文件中包含的行数组。
1 2 3 4
| foreach(file('myfile.txt') as $line) {
echo $line."
";
} |
-
一个GB文件将全部读入内存并转换为多个GB阵列...祝你好运。
-
这不是问题的答案,但它确实回答了许多人在这里看到的更常见的问题,所以它仍然有用,谢谢。
-
file()非常便于使用小文件。特别是当你想要一个array()作为最终结果时。
-
对于较大的文件,这是一个坏主意,因为整个文件一次被读取到一个数组
-
这会对大文件造成严重影响,因此它正是不起作用的方法。
1 2 3
| foreach (new SplFileObject(__FILE__) as $line) {
echo $line;
} |
-
一定要喜欢oneliners
-
Onestatementers。
所有答复都没有明显的答案。
PHP有一个整洁的流分隔符解析器,可用于此目的。
-
fopen需要2个参数。
-
@AkimKelar在这种情况下,这怎么会不合适?它是为这个案例和fgets的现代替代品而制作的。很高兴能解释一下这不是"合适的"
-
如果你不用错误的陈述污染答案我真的很感激。
小心'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); |
-
你如何确保1024 * 1024的块不会在行中间断开?
-
@ user151496容易!!数... 1.2.3.4
在处理大型文件时,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;
} |
-
这将在内存中创建一个超过一GB的单个数组(祝它好运)除了行甚至是任意的4096个字符块。为什么你想要这样做呢?