fwrite 不能写到文件头部,因为其写入位置由 fopen 的 mode 决定:如 "w" 或 "w+" 模式使指针归零,而 "a" 模式强制追加到末尾;fwrite 仅向当前指针位置写入数据,不控制指针移动。

fwrite 本身不会“写到文件头部”,真正决定写入位置的是 fopen 打开时用的模式 —— 比如 "w" 或 "w+" 才会让指针落在开头,而 "a" 永远追加到末尾。
为什么 fwrite 写不到头部?先看 fopen 的 mode 行为
很多人以为 fwrite 能控制写入位置,其实它只是把数据“塞进当前指针所在位置”。指针在哪,由 fopen 的 mode 决定:
-
"w":清空文件、指针归零 → 后续fwrite自然从头覆盖 -
"a":不清理、指针直接跳到末尾 →fwrite只能追加 -
"r+":文件必须存在、指针在开头 → 可读可写,但写入会覆盖原内容(不自动移位) -
"w+":文件存在则清空、指针归零 → 适合先写后读,但读前得rewind()或fseek()
错误现象:fopen('log.txt', 'a'); fwrite($fp, 'new line'); 总是加在最后,哪怕你期望插在开头 —— 这不是 fwrite 的错,是 "a" 模式锁死了位置。
fwrite 返回 false 的常见原因和检查方式
fwrite 失败时返回 false,但错误信息常被忽略。最典型的问题不是函数本身,而是上游资源没准备好:
立即学习“PHP免费学习笔记(深入)”;
-
fopen返回false(权限不足、路径不存在、open_basedir限制),后续fwrite($fp, ...)就会报Warning: fwrite() expects parameter 1 to be resource, bool given - 没检查
fopen返回值,直接传false给fwrite - 文件系统只读(比如容器挂载为 ro)、磁盘满、SELinux 限制
-
fwrite写入中文但文件编码与脚本不一致,部分字节写入失败(尤其没指定length且含多字节字符时)
实操建议:永远先判断 $fp = fopen(...) 是否为 resource:
<?php
$fp = fopen('data.txt', 'w');
if ($fp === false) {
$error = error_get_last();
trigger_error('fopen failed: ' . ($error['message'] ?? 'unknown'), E_USER_WARNING);
return;
}
if (fwrite($fp, "hello\n") === false) {
trigger_error('fwrite failed', E_USER_WARNING);
}
fclose($fp);
?>
w 和 w+ 模式下读写混合的陷阱
用 "w+" 打开后直接 fwrite 再 fread,很可能读不到刚写的内容 —— 因为写完指针停在末尾,fread 从那里开始读,自然为空。
- 必须显式重置指针:
rewind($fp)或fseek($fp, 0) -
"w+"会清空原文件,哪怕你只想读旧内容再改写一部分 —— 这时该用"r+"并手动ftruncate()控制长度 -
"x"和"x+"更安全:文件已存在就直接失败,避免误覆盖关键配置或日志
示例:想在开头插入一行,又保留原内容?"w" 不行,得靠临时文件或读取全部内容后拼接再重写 —— fwrite 本身不支持“插入”语义。
大文件或高频写入时的性能注意点
fwrite 是阻塞式同步写,每次调用都可能触发系统调用。高频小写入(比如每条日志都 fopen + fwrite + fclose)效率极低:
- 避免反复打开关闭:保持句柄复用,写完一批再
fclose - 不要用
file_put_contents($file, $data, FILE_APPEND)替代fopen("a") + fwrite做高频追加 —— 它每次都会重新打开文件,开销更大 - 二进制写入务必确认
$data是原始字节流,别混入mb_convert_encoding后的字符串,否则fwrite可能截断 - PHP 7.4 中
fwrite的$length参数可为null(PHP 8.0+ 才正式允许),7.4 下传null会警告,需显式省略或传具体整数
真正容易被忽略的点:文件锁。多个进程同时用 "w" 写同一文件,后打开的会清空先打开但还没 fclose 的内容 —— flock() 不是默认行为,得自己加。



















