对于 C/C++ 程序员。
fscanf() 的工作原理与 C/C++ 不同,因为 PHP 的 fscanf() 会隐式地将文件指针移动到下一行。
(PHP 4 >= 4.0.1, PHP 5, PHP 7, PHP 8)
fscanf — 根据格式解析文件中的输入
函数 fscanf() 类似于 sscanf(),但它从与 stream
关联的文件中获取输入,并根据指定的 format
解释输入。
格式字符串中的任何空格都与输入流中的任何空格匹配。这意味着,即使格式字符串中的制表符 (\t
) 也可以与输入流中的单个空格字符匹配。
每次调用 fscanf() 都从文件中读取一行。
如果此函数只传递了两个参数,则解析的值将作为数组返回。否则,如果传递了可选参数,则函数将返回分配的值数量。可选参数必须通过引用传递。
如果 format
中预期的子字符串数量多于 string
中可用的数量,则将返回 null
。在其他错误情况下,将返回 false
。
示例 #1 fscanf() 示例
<?php
$handle = fopen("users.txt", "r");
while ($userinfo = fscanf($handle, "%s\t%s\t%s\n")) {
list ($name, $profession, $countrycode) = $userinfo;
//... 对这些值执行某些操作
}
fclose($handle);
?>
示例 #2 users.txt 的内容
javier argonaut pe hiroshi sculptor jp robert slacker us luigi florist it
对于 C/C++ 程序员。
fscanf() 的工作原理与 C/C++ 不同,因为 PHP 的 fscanf() 会隐式地将文件指针移动到下一行。
最好在 fscanf 文档中说明
一次调用该函数,会读取完整的一行。
而不是仅仅读取格式中定义的值数量。
如果一个文本文件包含 2 行,每行包含 4 个整数值,
使用 8 个 fscanf($fd,"%d",$v) 读取文件,不会运行!
您必须执行 2 次
fscanf($fd,"%d %d %d %d",$v1,$v2,$v3,$v4);
然后每行 1 个 fscanf。
如果您想读取 csv 格式的文本文件或类似文件(无论字段使用什么字符分隔),您应该使用 fgetcsv()。当字段的文本为空时,fscanf() 可能会跳过它并用下一个文本填充它,而 fgetcsv() 会正确地将其视为一个空字段。
另一个用于读取文件并通过分隔符返回记录/字符串的函数。它与 fgets() 非常类似,只是分隔符是额外的参数。跨多行都能完美地工作。
function fgetd(&$rFile, $sDelim, $iBuffer=1024) {
$sRecord = '';
while(!feof($rFile)) {
$iPos = strpos($sRecord, $sDelim);
if ($iPos === false) {
$sRecord .= fread($rFile, $iBuffer);
} else {
fseek($rFile, 0-strlen($sRecord)+$iPos+strlen($sDelim), SEEK_CUR);
return substr($sRecord, 0, $iPos);
}
}
return false;
}
如果您想解析 cron 文件,可以使用此模式
<?php
while ($cron = fscanf($fp, "%s %s %s %s %s %[^\n]s"))
{
}
?>
实际上,与其尝试考虑文件中可能存在的每个字符,不如排除分隔符更轻松。
例如,如果您的分隔符是逗号,请使用
%[^,]
而不是
%[a-zA-Z0-9.| ... ]
只需确保在最后一个条目中使用 %[^,\n],这样您就不会包含换行符。
如果您希望 fscanf() 在大量行中扫描一个变量,例如一行中包含多个变量的 IP 地址,则可以使用 fscanf 与 explode()
<?
$filename = "somefile.txt";
$fp = fopen($filename, "r") or die ("Error opening file! \n");
$u = explode(" ",$line); // $u 是变量,例如 IP 地址
while ($line = fscanf($fp,"%s",$u)) {
if(preg_match("/^$u/",$_SERVER['REMOTE_ADDR'])) {$badipadresss++;} // 执行某些操作并继续扫描
}
?>
此外,fscanf() 比 fgets() 快得多
我发现 fscanf 的工作方式有点奇怪。 你可能需要使用集合而不是简单的 %s。 因为 fscanf 的工作方式与 C/C++ 大相径庭,所以它没有能力在字符串中提前扫描并正确匹配模式,因此看似完美的函数调用,例如:
fscanf($fh, "%s::%s");
对于类似这样的文件:
user::password
将不起作用。 当 fscanf 寻找字符串时,它只会查找并停止在空格处,因此 :: 以及除空格之外的所有内容都将被视为该字符串的一部分。 但是,你可以通过以下方式使它更聪明一些:
fscanf($fh, "%[a-zA-Z0-9,. ]::%[a-zA-Z0-9,. ]" $var1, $var2);
这告诉它,它只能接受 a 到 z、A 到 Z、0 到 9、逗号、句号和空格作为字符串的输入。 其他任何字符都将导致它停止接收输入并继续解析该行。 如果您希望将一个句子放入字符串中,并且不确定要添加多少个单词,等等,这将非常有用。
在 ACM 提交中使用 PHP 代码
这是一个使用 PHP 解决问题 1001 的示例解决方案
<?php
while (fscanf(STDIN, "%d%d", $a, $b) == 2) {
print ($a + $b) . "\n";
}