ftruncate() 总是返回 false 的根本原因是文件未以可写模式打开;必须使用 "r+"、"a+" 等含写权限的模式,而非 "r";同时需确保文件存在且可写,并注意截断后文件指针位置不变,需 rewind() 或 clearstatcache() 才能正确读取新大小。

ftruncate() 要求文件句柄必须以可写模式打开,且不能只读;直接用 fopen("file.txt", "r") 会失败——这是最常卡住的地方。
为什么 ftruncate() 总是返回 false?
根本原因通常是文件打开模式不满足写入前提。PHP 的 ftruncate() 不接受只读句柄,哪怕你只是想“缩短”它。
-
fopen($file, "r")→ 失败:权限不足,ftruncate()直接返回false -
fopen($file, "r+")→ 可行:保持原有内容,允许读写和截断 -
fopen($file, "a+")→ 可行:追加模式下也能截断,但注意文件指针默认在末尾,ftruncate()不会移动它 -
fopen($file, "w")→ 危险:会清空整个文件,再ftruncate()就没意义了
另外,确认文件存在且可写:is_writable($file) 建议前置检查,避免静默失败。
ftruncate() 后文件内容没变?
ftruncate() 不改变文件指针位置,也不刷新缓冲区——你读出来的还是旧内容,除非手动重定位或重新打开。
- 如果刚截断完就用
fread(),很可能读到原长度的残留数据(尤其在"r+"模式下) - 用
rewind($handle)把指针拉回开头,再读才反映新长度 - 或者关掉句柄后调用
clearstatcache(),再用filesize()验证磁盘实际大小 - 别依赖
fstat($handle)["size"],它可能缓存旧值
截断到比原文件还大的 size 怎么办?
可以,但结果不是“复制填充”,而是用 null 字节(\0)补满空白区域——这在二进制文件中要特别小心。
-
ftruncate($fp, 2048)对一个 512 字节的文件:末尾增加 1536 个\0 - 后续用
fwrite()写入时,这些 null 区域会被覆盖,但若直接fread()全部内容,会读出一堆\0 - 对文本日志这类场景,扩展后直接写新内容没问题;但对图像、压缩包等二进制文件,盲目扩展可能破坏结构
真正容易被忽略的是:截断操作本身不保证原子性,多进程同时操作同一文件时,必须配合 flock() 加锁——否则一个进程刚 ftruncate() 完,另一个进程的 fwrite() 可能写到已被删去的偏移上。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











