在C++开发涉及磁盘存储管理的场景时,获取文件系统的底层块大小和存储配额统计信息是核心需求,这些信息可以用于判断磁盘剩余空间、规划文件存储策略、监控存储使用情况等。不同操作系统的实现方式存在差异,本文以Linux和类Unix系统为例,介绍基于POSIX标准的实现方案。

核心接口与数据结构
在Linux和类Unix系统中,获取文件系统统计信息的标准接口是statvfs函数,该函数定义在sys/statvfs.h头文件中,对应的数据结构是struct statvfs,其中包含了块大小和存储配额相关的核心字段。
statvfs结构体关键字段说明
| 字段名 | 含义 |
|---|---|
| f_bsize | 文件系统的首选块大小,是进行IO操作时的推荐块大小 |
| f_frsize | 文件系统的基础块大小,是统计块数量时使用的基本单位 |
| f_blocks | 文件系统中总的块数量(以f_frsize为单位) |
| f_bfree | 文件系统中未使用的块数量(以f_frsize为单位) |
| f_bavail | 非特权用户可使用的未使用块数量(以f_frsize为单位) |
| f_files | 文件系统中总的inode数量 |
| f_ffree | 文件系统中未使用的inode数量 |
| f_favail | 非特权用户可使用的未使用inode数量 |
获取块大小和存储配额的完整实现
下面的代码示例展示了如何调用statvfs接口,获取指定路径所在文件系统的块大小和存储配额详细信息,并进行单位转换方便阅读。
#include <iostream>
#include <sys/statvfs.h>
#include <cstring>
#include <cerrno>
// 单位转换函数,将字节数转换为合适的单位
void format_size(unsigned long long bytes, char* buffer, size_t buffer_size) {
const char* units[] = {"B", "KB", "MB", "GB", "TB"};
int unit_index = 0;
double size = static_cast<double>(bytes);
while (size >= 1024.0 && unit_index < 4) {
size /= 1024.0;
unit_index++;
}
snprintf(buffer, buffer_size, "%.2f %s", size, units[unit_index]);
}
int main() {
const char* target_path = "/"; // 要查询的文件系统路径,这里查询根目录所在文件系统
struct statvfs fs_info;
// 调用statvfs获取文件系统信息
if (statvfs(target_path, &fs_info) != 0) {
std::cerr << "获取文件系统信息失败,错误原因:" << strerror(errno) << std::endl;
return 1;
}
// 计算基础块大小、总容量、剩余容量、可用容量
unsigned long block_size = fs_info.f_frsize;
unsigned long long total_blocks = fs_info.f_blocks;
unsigned long long free_blocks = fs_info.f_bfree;
unsigned long long avail_blocks = fs_info.f_bavail;
unsigned long long total_bytes = total_blocks * block_size;
unsigned long long free_bytes = free_blocks * block_size;
unsigned long long avail_bytes = avail_blocks * block_size;
// 计算inode相关信息
unsigned long long total_inodes = fs_info.f_files;
unsigned long long free_inodes = fs_info.f_ffree;
unsigned long long avail_inodes = fs_info.f_favail;
// 输出结果
char size_buffer[32];
std::cout << "目标路径:" << target_path << std::endl;
std::cout << "文件系统基础块大小:" << block_size << " 字节" << std::endl;
std::cout << "文件系统首选块大小:" << fs_info.f_bsize << " 字节" << std::endl;
format_size(total_bytes, size_buffer, sizeof(size_buffer));
std::cout << "总存储容量:" << size_buffer << std::endl;
format_size(free_bytes, size_buffer, sizeof(size_buffer));
std::cout << "总剩余容量(含特权预留):" << size_buffer << std::endl;
format_size(avail_bytes, size_buffer, sizeof(size_buffer));
std::cout << "非特权用户可用容量:" << size_buffer << std::endl;
std::cout << "总inode数量:" << total_inodes << std::endl;
std::cout << "剩余inode数量(含特权预留):" << free_inodes << std::endl;
std::cout << "非特权用户可用inode数量:" << avail_inodes << std::endl;
return 0;
}
代码说明与注意事项
上述代码中,首先调用statvfs函数传入目标路径,获取对应文件系统的统计信息。需要注意f_bsize和f_frsize的区别:f_bsize是文件系统推荐的IO块大小,而f_frsize是统计容量时的基本块单位,计算总容量时需要使用f_frsize乘以总块数。
存储配额相关的统计中,f_bfree包含了系统为特权用户预留的存储空间,普通用户无法使用这部分空间,因此实际可用容量需要使用f_bavail计算。如果是在Windows系统下开发,无法使用statvfs接口,需要调用Windows API中的GetDiskFreeSpaceEx函数实现类似功能。
常见问题解答
为什么获取到的块大小和实际磁盘物理块大小不一致
文件系统的块大小是逻辑块大小,和磁盘的物理扇区大小没有必然关系,是文件系统格式化时设置的参数,用于管理文件存储的分配单元。
如何查询指定文件的存储空间占用
如果需要查询单个文件的存储占用,可以使用stat接口,通过struct stat中的st_blocks字段获取文件占用的块数量,再结合文件系统的块大小计算实际占用空间。