fstat()仅适用于已打开的文件句柄,核心价值在于避免重复打开的开销与竞争风险;必须先用fopen()等获取有效resource,返回数组中仅size、atime、mtime、ctime、mode、dev、ino跨平台可靠,其余字段可能为-1。

fstat() 不是替代 filesize() 或 stat() 的万能函数,它只在你**已经打开文件且需要同步获取元数据**时才有实际价值。直接用 filesize() 更快,用 stat() 更灵活;fstat() 的存在意义,是避免重复打开文件带来的开销或竞争风险。
为什么必须先 fopen() 才能用 fstat()?
fstat() 依赖内核对已打开文件描述符(fd)的缓存视图,不是读取磁盘 inode。如果传入未打开的句柄,PHP 会报 Warning: fstat(): supplied resource is not a valid stream resource。
- 必须用
fopen()、fsockopen()等返回有效 resource 的方式打开文件 - 不能用
file_get_contents()后的临时资源——它不暴露底层 file descriptor - 不能对
STDIN、php://memory等伪协议使用(多数返回-1或空数组)
fstat() 返回数组里哪些字段可靠?
不同系统(Linux/macOS/Windows)、不同 PHP SAPI(CLI/FPM)、不同文件系统(ext4/ZFS/NFS),会导致部分字段为 -1 或缺失。真正跨平台稳定的只有:
-
size:总是准确,等价于filesize(),但无需额外系统调用 -
atime、mtime、ctime:Unix 时间戳,但 Windows 下atime可能不更新(需挂载选项noatime或关闭) -
mode:权限掩码(如33188≈0644),可用octdec(sprintf('%o', $info['mode']))转换 -
dev和ino:可用于判断是否为同一文件(硬链接检测),但 NFS 挂载下可能不唯一
而 blksize、blocks、rdev 在 Windows 或某些容器环境里常为 -1,不应依赖。
和 stat()、filesize() 比,fstat() 的真实优势在哪?
关键在于「原子性」和「上下文一致性」——当你已经持有一个打开的文件句柄,并准备紧接着读写时,fstat() 获取的状态与后续 fread()/fwrite() 操作基于同一 fd 视图,不会因外部修改导致状态错位。
- 例如:上传临时文件后立即检查大小+权限,再决定是否 move —— 用
fstat($fp)比先fclose()再stat($path)少一次 open syscall,也规避了 race condition - 流式处理大文件时,边读边监控
size和mtime是否变化(防止被截断或覆盖) - 配合
flock()做文件锁校验:锁住后fstat()确认 size 未变,再继续解析
但注意:fstat() 不会刷新 atime,哪怕你只是调用它——这点和 stat() 一致,和真正访问文件不同。
常见坑:远程文件、符号链接、关闭后调用
三个高频翻车点:
-
fstat()对http://、ftp://等远程 URL 失效,fopen()虽能打开,但fstat()返回 false 或空数组——PHP 不支持远程文件的 inode 查询 - 对符号链接,默认返回链接目标的 stat 信息(和
stat()行为一致),不是链接本身的属性;若要查链接本身,得用lstat(),但没有flstat() - 文件句柄关闭后调用
fstat()会触发 warning 并返回 false,且不会抛出异常——务必在fclose()前完成所有fstat()调用
最稳妥的写法永远是:$fp = fopen($path, 'rb'); if ($fp) { $stat = fstat($fp); fclose($fp); },别省那行 if 判断。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











