2024年PHP开发者大会(日本)

fgets

(PHP 4, PHP 5, PHP 7, PHP 8)

fgets从文件指针读取一行

描述

fgets(资源 $stream, ?整数 $length = null): 字符串|false

从文件指针读取一行。

参数

stream

文件指针必须有效,并且必须指向由 fopen()fsockopen() 成功打开(并且尚未由 fclose() 关闭)的文件。

length

读取在读取了 length - 1 个字节、遇到换行符(包含在返回值中)或遇到文件末尾 (EOF) 时结束(以先到者为准)。如果未指定长度,它将继续从流中读取,直到到达行尾。

返回值

返回从 stream 指向的文件中读取的最多 length - 1 个字节的字符串。如果文件指针中没有更多数据可读取,则返回 false

如果发生错误,则返回 false

范例

示例 #1 按行读取文件

<?php

$fp
= @fopen("/tmp/inputfile.txt", "r");

if (
$fp) {
while ((
$buffer = fgets($fp, 4096)) !== false) {
echo
$buffer, PHP_EOL;
}

if (!
feof($fp)) {
echo
"Error: unexpected fgets() fail\n";
}

fclose($fp);
}

?>

注释

注意: 如果PHP在读取Macintosh计算机上或由其创建的文件时无法正确识别换行符,启用 auto_detect_line_endings 运行时配置选项可能会帮助解决此问题。

注意:

习惯了fgets() 的“C”语义的人应该注意EOF返回方式的差异。

参见

添加注释

用户贡献的注释 5条注释

20
Leigh Purdie
9年前
一个更好的例子,用于说明对于大型文件,fgets 和 stream_get_line 之间的速度差异。

此示例模拟您从输入源读取可能很长、长度不确定(但具有最大缓冲区大小)的行的情况。

正如Dade 指出的那样,我之前提供的示例太容易被拆解,并没有充分突出我试图解决的问题。

请注意,为fgets指定明确的结束字符(例如:换行符)通常会相当显著地降低速度差异。

#!/usr/bin/php
<?php
$plaintext
=file_get_contents('http://loripsum.net/api/60/verylong/plaintext'); # 字符数约为90k
$plaintext=str_replace("\n"," ",$plaintext); # 去除换行符

$fp=fopen("/tmp/SourceFile.txt","w");
for(
$i=0;$i<100000;$i++) {
fputs($fp,substr($plaintext,0,rand(4096,65534)) . "\n");
}
fclose($fp);

$fp=fopen("/tmp/SourceFile.txt","r");
$start=microtime(true);
while(
$line=fgets($fp,65535)) {
1;
}
$end=microtime(true);
fclose($fp);
$delta1=($end - $start);

$fp=fopen("/tmp/SourceFile.txt","r");
$start=microtime(true);
while(
$line=stream_get_line($fp,65535)) {
1;
}
$end=microtime(true);
fclose($fp);
$delta2=($end - $start);

$pdiff=$delta1/$delta2;
print
"stream_get_line 比 fgets 更快 - pdiff 为 ". ($pdiff>1?"faster":"slower") . " - pdiff is $pdiff\n";
?>

$ ./testcase.php
stream_get_line 比 fgets 更快 - pdiff 为 1.760398041785

请注意,在大多数使用 php 的情况下,系统调用之间细微的速度差异无关紧要。
3
匿名用户
4年前
如果你出于某种原因需要从字符串而不是文件指针中获取行,请尝试:

<?php
function string_gets(string $source, int $offset = 0, string $delimiter = "\n"): ?string
{
$len = strlen($source);
if (
$len < $offset) {
// 越界..也许我应该抛出一个异常
return null;
}
if (
$len === $offset) {
// 字符串结尾..
return null;
}
$delimiter_pos = strpos($source, $delimiter, $offset);
if (
$delimiter_pos === false) {
// 最后一行。
return substr($source, $offset);
}
return
substr($source, $offset, ($delimiter_pos - $offset) + strlen($delimiter));
}

?>

(我需要逐行处理一个大约 16GB 的内存中字符串,但是如果我尝试使用 explode("\n",$str);,我会在 32GB 内存的系统上出现内存分配崩溃,所以我采用了这种方法..有趣的是,fgets() 似乎比在 php 中的内存中处理更快。php 7.3.7)
4
David at Weintraub.name
17年前
文档中存在错误

文件指针必须有效,并且必须指向由 fopen() 或 fsockopen() 成功打开的文件(并且尚未由 fclose() 关闭)。

你还应该在文档中添加“popen”和“pclose”。我是一个新的 PHP 开发人员,我想验证我是否可以在我使用“popen”的命令上使用“fgets”。
2
Peter Schlaile
17年前
fscanf($file, "%s\n") 并不是 fgets() 的一个好的替代品,因为它会在第一个空格处停止解析,而不是在行尾停止!

(有关此方面的详细信息,请参阅 fscanf 页面)
1
tavernadelleidee[italy]
18年前
我认为读取具有反向顺序行的(长)文件的最快方法是

<?php
$myfile
= 'myfile.txt';
$command = "tac $myfile > /tmp/myfilereversed.txt";
passthru($command);
$ic = 0;
$ic_max = 100; // 读取指定行数后停止
$handle = fopen("/tmp/myfilereversed.txt", "r");
while (!
feof($handle) && ++$ic<=$ic_max) {
$buffer = fgets($handle, 4096);
echo
$buffer."<br>";
}
fclose($handle);
?>

它在读取文件时回显行,因此它对于长文件(如日志)非常有用。

Borgonovo
To Top