statvfs() 是获取文件系统块与inode信息的唯一可靠POSIX接口,需传挂载点路径,用f_bavail*f_frsize算可用空间、f_favail判inode耗尽;Windows无等价机制,须用GetDiskFreeSpaceEx()配合业务限流。

statvfs() 是获取文件系统配额与块信息的唯一可靠接口
Linux/macOS 上没有跨平台的“获取磁盘配额” C++ 标准库函数,statvfs() 是 POSIX 定义的底层事实标准。它不返回用户/组配额(那是 quotactl() 的事),但能准确告诉你:总块数、可用块数、最小可用块(考虑 root 保留)、块大小、总/可用 inode 数——这些才是判断“还能不能写入”“是否 inode 耗尽”的关键。
常见误用是拿 stat() 或 std::filesystem::space() 替代——它们只返回挂载点路径的统计,且 std::filesystem::space() 在 glibc 2.35+ 之前甚至不填充 available 字段(返回 0),在容器或 NFS 挂载下更不可靠。
实操建议:
-
statvfs()必须传入**挂载点路径**(如"/"、"/home"),不是任意文件路径;传错会返回上层挂载点数据 - 检查返回值:失败时返回 -1,
errno可能是ENOTDIR(路径非目录)、EBADF(路径无效)或EACCES(无权限读挂载点) - 注意字段单位:
f_frsize是“基本块大小”(通常等于f_bsize),所有f_blocks/f_bfree等都以该单位计数,不是字节
计算真实可用空间要避开 f_bavail 和 f_bfree 的混淆
f_bfree 是所有未分配块数,f_bavail 是**普通用户实际可用块数**(已扣除 root 保留空间,默认 5%,可通过 tune2fs -m 修改)。写入程序必须用 f_bavail 判断是否将满,否则可能因保留空间触发 “No space left on device” 错误,即使 df 显示还有 5% 剩余。
换算为字节的正确公式是:f_bavail * fs.f_frsize(不是 f_bsize,虽然多数情况相等,但 POSIX 要求用 f_frsize)。
容易踩的坑:
- 直接用
f_blocks * f_bsize计算总容量 → 错,应为f_blocks * f_frsize - 把
f_bavail当作“剩余百分比”使用 → 错,它是绝对块数,需自行除以f_blocks才得比例 - 忽略
f_flag & ST_RDONLY就尝试写入 → 应先检查文件系统是否只读,避免后续操作失败
inode 统计只能靠 statvfs(),无法用 opendir() 遍历替代
有人想通过递归 opendir() + readdir() 统计 inode 数量,这既慢又不准:符号链接、硬链接、proc/sysfs 等虚拟文件系统不适用;权限不足目录会跳过;NFS 挂载可能返回 stale handle。而 statvfs() 的 f_files、f_ffree、f_favail 是内核维护的实时计数,开销近乎为零。
根据 package.json 中的 engines 字段自动检测 Node.js 版本需求,未安装 nvm 时自动安装并切换至对应版本。支持 Windows、macOS、Linux。适用于 Node.js 项目开发、版本切换和环境配置。
关键点:
-
f_favail是普通用户可用 inode 数(类似f_bavail对块的作用),f_ffree是总空闲 inode 数 - 当
f_favail == 0时,新建文件/目录必然失败(ENOSPC),与磁盘空间满同级严重 - 某些旧版内核(如 2.4)或网络文件系统(CIFS)可能不支持 inode 统计,此时
f_files为 0,需降级处理(例如记录警告并仅依赖块统计)
Windows 上没有 statvfs(),必须用 GetDiskFreeSpaceEx() + WMI 补全 inode 类比项
Windows 不提供 inode 概念,也没有等价的“文件数限制”内核统计。GetDiskFreeSpaceEx() 只能返回总/可用字节数(对应 statvfs() 的块统计部分),且其 lpFreeBytesAvailable 已自动扣除系统保留空间,行为更接近 f_bavail。
若需类比 inode 状态(比如防止单目录创建过多小文件),只能借助 WMI 查询 Win32_Volume 的 Capacity 和 FreeSpace,但依然无文件计数。实际工程中,更可行的是业务层限流(如单目录不超过 10 万文件)或监控 CreateFile() 失败时的 GetLastError() 是否为 ERROR_HANDLE_DISK_FULL(Windows 会在此类资源耗尽时复用该错误码)。
跨平台封装提示:
- 不要试图抽象出统一的 “InodeInfo” 结构体传给 Windows —— 它根本不存在
- Linux/macOS 用
statvfs();Windows 用GetDiskFreeSpaceEx(),二者返回结构体字段命名、语义均不同,硬对齐只会引入 bug - 块大小在 Windows 上固定为簇(cluster)大小,由
GetDiskFreeSpace()返回,不是可配置项
真正麻烦的从来不是调哪个函数,而是理解 f_bavail 和 f_favail 这两个字段背后代表的权限模型差异——它们不是技术细节,是操作系统对“谁有资格用这块资源”的明确表态。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










