file_put_contents() 默认覆盖写入,等价于 fopen(..., 'w') 截断文件;追加需显式传 file_append;高并发下追加需 lock_ex;大文件建议临时文件+rename() 保证原子性。

file_put_contents() 默认就是覆盖写入
PHP 的 file_put_contents() 函数在目标文件已存在时,**默认行为就是清空原内容、重新写入**,不需要额外配置。它不是“追加”,也不是“报错”,而是静默覆盖——这点常被误认为需要加参数才能覆盖。
- 直接调用
file_put_contents('a.txt', 'hello'),如果a.txt已存在,原内容会彻底丢失 - 底层等价于先
fopen(..., 'w')再写入,'w' 模式天然截断文件 - 若想避免意外覆盖,必须手动检查文件是否存在,或改用
FILE_APPEND标志
想追加而不是覆盖?必须显式传 FILE_APPEND
很多人以为不加标志就是“安全模式”,结果发现日志越写越长——其实是忘了加标志才导致覆盖。反过来,要追加内容,必须显式传入 FILE_APPEND,否则永远是覆盖。
-
file_put_contents('log.txt', "new line\n", FILE_APPEND)→ 正确追加 -
file_put_contents('log.txt', "new line\n")→ 覆盖整个文件,只留这一行 - 多个写入操作之间没有自动锁机制,高并发下追加可能乱序(需配合
LOCK_EX)
覆盖写入时要注意权限和原子性
覆盖看似简单,但线上环境常因权限或进程竞争出问题。比如 Web 服务器用户(如 www-data)没权限删/重命名旧文件,或另一个 PHP 进程正在读取它,就可能导致写入失败或内容损坏。
- 确保目标路径可写:
is_writable(dirname($path))建议提前校验 - 大文件覆盖建议用临时文件 +
rename()替换,避免中间状态暴露(file_put_contents()是原子的,但仅限小文件;大文件写入中途崩溃会导致残缺 - Windows 下对正在被读取的文件覆盖会失败(
Permission denied),Linux 一般允许
替代方案:fopen() + fwrite() 更可控
当需要精细控制(比如写前校验、写后 chmod、捕获具体错误类型),fopen() 显式打开比 file_put_contents() 更可靠。
立即学习“PHP免费学习笔记(深入)”;
-
fopen($path, 'w')明确表达“覆盖意图”,语义清晰 - 可立即检查返回值:
if (!$fp) { throw new RuntimeException("Cannot open $path for writing"); } - 写完可用
fclose($fp)确保缓冲区落盘,再做后续操作(如chmod()) - 注意:不要混用
fwrite()和file_put_contents()操作同一文件,缓存和锁行为不一致
file_exists() 或备份逻辑,远比事后恢复省事。











