mixed fscanf ( resource $handle , string $format [, mixed &$... ] )
| 参数 | 描述 |
|---|---|
handle |
文件指针资源,通常由fopen()函数创建 |
format |
格式化字符串,指定如何解析输入数据 |
... |
可选的可变参数,用于存储解析后的值(按引用传递) |
| 说明符 | 描述 | 示例 |
|---|---|---|
%s |
字符串(直到遇到空白字符) | "hello" |
%d |
有符号十进制整数 | 123, -456 |
%u |
无符号十进制整数 | 123, 456 |
%f, %F |
浮点数 | 3.14, -2.5 |
%c |
单个字符 | 'a', 'B' |
%x, %X |
十六进制整数 | 1a, FF |
%o |
八进制整数 | 777, 123 |
%% |
字面百分号 | % |
%[^] |
匹配字符集 | %[a-z] 匹配小写字母 |
false<?php
// 创建测试文件
$content = "John 25 75.5\nAlice 30 65.2\nBob 28 80.1";
file_put_contents('data.txt', $content);
// 打开文件
$handle = fopen('data.txt', 'r');
if (!$handle) {
die('无法打开文件');
}
// 方法1:返回数组
rewind($handle);
while ($data = fscanf($handle, "%s %d %f")) {
if ($data !== false) {
list($name, $age, $score) = $data;
echo "姓名: $name, 年龄: $age, 分数: $score<br>";
}
}
echo "<hr>";
// 方法2:使用可变参数
rewind($handle);
while (fscanf($handle, "%s %d %f", $name, $age, $score) !== false) {
if ($name !== null) {
echo "姓名: $name, 年龄: $age, 分数: $score<br>";
}
}
fclose($handle);
// 清理
unlink('data.txt');
?>
<?php
// 创建配置文件
$config = "
# 数据库配置
db_host = localhost
db_port = 3306
db_name = mydatabase
db_user = admin
db_pass = secret123
# 应用配置
app_name = MyApp
app_debug = true
app_version = 2.5.1
";
file_put_contents('config.txt', $config);
// 解析配置文件
function parseConfigFile($filename) {
$config = [];
$handle = fopen($filename, 'r');
if (!$handle) {
return false;
}
while (!feof($handle)) {
$line = fgets($handle);
// 跳过注释和空行
if (trim($line) === '' || $line[0] === '#') {
continue;
}
// 解析键值对
if (fscanf($handle, "%[^=] = %[^\n]", $key, $value) === 2) {
$key = trim($key);
$value = trim($value);
// 处理布尔值
if ($value === 'true') {
$value = true;
} elseif ($value === 'false') {
$value = false;
}
// 处理数字
elseif (is_numeric($value)) {
if (strpos($value, '.') !== false) {
$value = (float)$value;
} else {
$value = (int)$value;
}
}
$config[$key] = $value;
}
// 由于fscanf移动了指针,需要调整
fseek($handle, ftell($handle));
}
fclose($handle);
return $config;
}
// 使用示例
$config = parseConfigFile('config.txt');
if ($config) {
echo "<h5>解析的配置:</h5>";
echo "<pre>" . print_r($config, true) . "</pre>";
}
// 清理
unlink('config.txt');
?>
<?php
// 创建CSV格式数据(包含不同类型)
$csvData = "Product,Price,Quantity,InStock
Laptop,999.99,50,true
Mouse,25.50,100,false
Keyboard,79.99,75,true
Monitor,299.99,30,true";
file_put_contents('inventory.csv', $csvData);
// 使用fscanf解析CSV
$handle = fopen('inventory.csv', 'r');
if (!$handle) {
die('无法打开文件');
}
// 读取标题行
$headers = fgetcsv($handle);
echo "<table class='table table-bordered'>";
echo "<thead><tr>";
foreach ($headers as $header) {
echo "<th>" . htmlspecialchars($header) . "</th>";
}
echo "</tr></thead><tbody>";
// 读取数据行
while (!feof($handle)) {
// 使用fscanf解析每行
$result = fscanf($handle, "%[^,],%f,%d,%s");
if ($result !== false && count($result) === 4) {
list($product, $price, $quantity, $inStock) = $result;
// 处理布尔值
$inStock = ($inStock === 'true') ? '是' : '否';
echo "<tr>";
echo "<td>" . htmlspecialchars($product) . "</td>";
echo "<td>\${$price}</td>";
echo "<td>{$quantity}</td>";
echo "<td>{$inStock}</td>";
echo "</tr>";
}
}
echo "</tbody></table>";
fclose($handle);
// 清理
unlink('inventory.csv');
?>
<?php
// 创建日志文件
$logData = <<<LOG
[2023-10-01 14:30:25] INFO: User login successful (user_id=123)
[2023-10-01 14:35:10] ERROR: Database connection failed (error_code=1001)
[2023-10-01 14:40:15] WARNING: High memory usage detected (usage=85%)
[2023-10-01 14:45:30] INFO: File uploaded successfully (file_size=2048576)
LOG;
file_put_contents('app.log', $logData);
// 解析日志文件
class LogParser {
private $handle;
public function __construct($filename) {
$this->handle = fopen($filename, 'r');
if (!$this->handle) {
throw new Exception("无法打开日志文件: $filename");
}
}
public function parseLine() {
if (feof($this->handle)) {
return false;
}
// 解析日志格式: [日期 时间] 级别: 消息 (键=值)
$result = fscanf(
$this->handle,
"[%10s %8s] %[^:]: %[^(] (%[^)]))"
);
if ($result === false || count($result) < 4) {
return false;
}
list($date, $time, $level, $message, $extra) = array_pad($result, 5, '');
// 解析额外参数
$params = [];
if (!empty($extra)) {
$pairs = explode(' ', $extra);
foreach ($pairs as $pair) {
list($key, $value) = explode('=', $pair, 2);
$params[$key] = $value;
}
}
return [
'timestamp' => "$date $time",
'level' => trim($level),
'message' => trim($message),
'params' => $params
];
}
public function getAllLogs() {
$logs = [];
while ($log = $this->parseLine()) {
$logs[] = $log;
}
return $logs;
}
public function __destruct() {
if ($this->handle) {
fclose($this->handle);
}
}
}
// 使用示例
try {
$parser = new LogParser('app.log');
$logs = $parser->getAllLogs();
echo "<h5>解析的日志条目:</h5>";
echo "<div class='table-responsive'>";
echo "<table class='table table-bordered table-sm'>";
echo "<thead class='table-light'>
<tr>
<th>时间</th>
<th>级别</th>
<th>消息</th>
<th>参数</th>
</tr>
</thead><tbody>";
foreach ($logs as $log) {
$levelClass = '';
switch ($log['level']) {
case 'ERROR': $levelClass = 'danger'; break;
case 'WARNING': $levelClass = 'warning'; break;
case 'INFO': $levelClass = 'info'; break;
}
echo "<tr>";
echo "<td>{$log['timestamp']}</td>";
echo "<td><span class='badge bg-{$levelClass}'>{$log['level']}</span></td>";
echo "<td>{$log['message']}</td>";
echo "<td>" . htmlspecialchars(json_encode($log['params'])) . "</td>";
echo "</tr>";
}
echo "</tbody></table></div>";
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
// 清理
unlink('app.log');
?>
fgets()配合sscanf()可能更灵活| 特性 | fscanf() | fgets() + sscanf() |
|---|---|---|
| 使用方式 | 一步完成读取和解析 | 先读取行,再解析 |
| 灵活性 | 较低,必须在读取时指定格式 | 较高,可以读取后再决定如何解析 |
| 错误处理 | 失败时返回false | 可以分别处理读取和解析错误 |
| 性能 | 对于简单格式较快 | 对于复杂处理更可控 |
| 推荐场景 | 结构化的固定格式文件 | 需要灵活处理或复杂解析的场景 |
sscanf() - 根据指定格式解析字符串fgets() - 从文件指针中读取一行fread() - 读取文件(二进制安全)fopen() - 打开文件或URLfclose() - 关闭一个已打开的文件指针file() - 将整个文件读入数组中preg_match() - 执行正则表达式匹配解析结构化的配置文件,如INI风格的键值对。
解析固定格式的日志文件,提取时间戳、级别和消息。
导入结构化的数据文件,如CSV或自定义格式的数据。
从模板文件中提取变量和占位符。