fstatfs 函数详解
1. 函数介绍
fstatfs
是 Linux 系统中用于获取文件系统统计信息的系统调用。可以把这个函数想象成一个”文件系统体检工具”——当你给它一个已打开的文件描述符时,它会告诉你这个文件所在文件系统的详细信息,比如总空间多大、已用多少、还剩多少、支持什么特性等等。
就像你去体检时医生会检查你的身高、体重、血压等指标一样,fstatfs
会检查文件系统的”健康状况”和”基本信息”。
2. 函数原型
#include <sys/vfs.h> /* 或者 #include <sys/statfs.h> */
int fstatfs(int fd, struct statfs *buf);
3. 功能
fstatfs
函数用于获取与指定文件描述符相关的文件系统的统计信息。它填充一个 statfs
结构体,其中包含了文件系统的各种参数和状态信息。
4. 参数
- fd: 已打开的文件描述符(可以是任何类型的文件:普通文件、目录、设备等)
- buf: 指向
struct statfs
结构体的指针,用于存储返回的文件系统信息
5. 返回值
- 成功: 返回 0
- 失败: 返回 -1,并设置相应的 errno 错误码
常见错误码:
EBADF
: fd 不是有效的文件描述符EFAULT
: buf 指针无效EIO
: I/O 错误ENOSYS
: 系统不支持此操作
6. 相似函数或关联函数
- statfs: 通过文件路径获取文件系统信息(需要文件路径而非文件描述符)
- statvfs: POSIX 标准的文件系统信息获取函数(提供更标准化的接口)
- fstatvfs: 通过文件描述符获取 POSIX 标准的文件系统信息
- stat: 获取文件本身的详细信息(不是文件系统信息)
7. struct statfs 结构体详解
struct statfs {
long f_type; /* 文件系统类型 */
long f_bsize; /* 文件系统块大小 */
long f_blocks; /* 总块数 */
long f_bfree; /* 空闲块数 */
long f_bavail; /* 对非超级用户可用的块数 */
long f_files; /* 总 inode 数 */
long f_ffree; /* 空闲 inode 数 */
fsid_t f_fsid; /* 文件系统 ID */
long f_namelen; /* 最大文件名长度 */
long f_frsize; /* 片段大小 */
long f_spare[5]; /* 保留字段 */
};
8. 示例代码
示例1:基础用法 – 查看文件系统空间信息
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/vfs.h>
int main() {
int fd;
struct statfs fs_info;
const char *filename = "/etc/passwd"; // 使用系统文件作为示例
// 打开文件
fd = open(filename, O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
// 获取文件系统信息
if (fstatfs(fd, &fs_info) == -1) {
perror("fstatfs");
close(fd);
return 1;
}
// 显示文件系统信息
printf("=== 文件系统信息 ===\n");
printf("文件: %s\n", filename);
printf("文件系统类型: 0x%lx\n", fs_info.f_type);
printf("块大小: %ld 字节\n", fs_info.f_bsize);
printf("总块数: %ld\n", fs_info.f_blocks);
printf("空闲块数: %ld\n", fs_info.f_bfree);
printf("可用块数: %ld\n", fs_info.f_bavail);
printf("总 inode 数: %ld\n", fs_info.f_files);
printf("空闲 inode 数: %ld\n", fs_info.f_ffree);
// 计算空间使用情况(以 GB 为单位)
double total_space = (double)(fs_info.f_blocks * fs_info.f_bsize) / (1024 * 1024 * 1024);
double free_space = (double)(fs_info.f_bfree * fs_info.f_bsize) / (1024 * 1024 * 1024);
double avail_space = (double)(fs_info.f_bavail * fs_info.f_bsize) / (1024 * 1024 * 1024);
printf("\n=== 空间使用情况 ===\n");
printf("总空间: %.2f GB\n", total_space);
printf("空闲空间: %.2f GB\n", free_space);
printf("可用空间: %.2f GB\n", avail_space);
printf("使用率: %.2f%%\n",
(total_space - free_space) / total_space * 100);
close(fd);
return 0;
}
示例2:文件系统类型识别
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/vfs.h>
// 常见文件系统类型的宏定义
#define EXT2_SUPER_MAGIC 0xEF53
#define EXT3_SUPER_MAGIC 0xEF53
#define EXT4_SUPER_MAGIC 0xEF53
#define XFS_SUPER_MAGIC 0x58465342
#define NTFS_SB_MAGIC 0x5346544E
#define TMPFS_MAGIC 0x01021994
#define PROC_SUPER_MAGIC 0x9FA0
#define SYSFS_MAGIC 0x62656572
// 根据文件系统类型返回字符串描述
const char* get_fs_type_name(long fs_type) {
switch (fs_type) {
case EXT2_SUPER_MAGIC:
return "ext2/ext3/ext4";
case XFS_SUPER_MAGIC:
return "XFS";
case NTFS_SB_MAGIC:
return "NTFS";
case TMPFS_MAGIC:
return "tmpfs";
case PROC_SUPER_MAGIC:
return "proc";
case SYSFS_MAGIC:
return "sysfs";
default:
return "未知文件系统";
}
}
int main() {
int fd;
struct statfs fs_info;
const char *test_files[] = {"/etc/passwd", "/proc/version", "/sys/kernel"};
int num_files = sizeof(test_files) / sizeof(test_files[0]);
for (int i = 0; i < num_files; i++) {
printf("\n=== 检查文件: %s ===\n", test_files[i]);
// 打开文件
fd = open(test_files[i], O_RDONLY);
if (fd == -1) {
perror("open");
printf("跳过此文件\n");
continue;
}
// 获取文件系统信息
if (fstatfs(fd, &fs_info) == -1) {
perror("fstatfs");
close(fd);
continue;
}
// 显示详细信息
printf("文件系统类型代码: 0x%lx\n", fs_info.f_type);
printf("文件系统类型名称: %s\n", get_fs_type_name(fs_info.f_type));
printf("最大文件名长度: %ld 字符\n", fs_info.f_namelen);
printf("片段大小: %ld 字节\n", fs_info.f_frsize);
close(fd);
}
return 0;
}
示例3:磁盘空间监控工具
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/vfs.h>
#include <string.h>
// 磁盘使用情况结构体
struct disk_usage {
char path[256];
double total_gb;
double used_gb;
double free_gb;
double usage_percent;
};
// 获取磁盘使用情况
int get_disk_usage(const char *filepath, struct disk_usage *usage) {
int fd;
struct statfs fs_info;
// 打开文件
fd = open(filepath, O_RDONLY);
if (fd == -1) {
perror("open");
return -1;
}
// 获取文件系统信息
if (fstatfs(fd, &fs_info) == -1) {
perror("fstatfs");
close(fd);
return -1;
}
// 填充使用情况结构体
strncpy(usage->path, filepath, sizeof(usage->path) - 1);
usage->path[sizeof(usage->path) - 1] = '\0';
// 计算空间大小(GB)
double block_size_gb = (double)fs_info.f_bsize / (1024 * 1024 * 1024);
usage->total_gb = fs_info.f_blocks * block_size_gb;
usage->free_gb = fs_info.f_bavail * block_size_gb; // 使用 f_bavail 而不是 f_bfree
usage->used_gb = usage->total_gb - usage->free_gb;
usage->usage_percent = (usage->used_gb / usage->total_gb) * 100;
close(fd);
return 0;
}
// 打印磁盘使用情况(带进度条效果)
void print_disk_usage(const struct disk_usage *usage) {
printf("路径: %s\n", usage->path);
printf("总空间: %.2f GB\n", usage->total_gb);
printf("已用空间: %.2f GB\n", usage->used_gb);
printf("可用空间: %.2f GB\n", usage->free_gb);
// 显示进度条
int bar_width = 50;
int filled_width = (int)((usage->usage_percent / 100) * bar_width);
printf("使用率: %.1f%% [", usage->usage_percent);
for (int i = 0; i < bar_width; i++) {
if (i < filled_width) {
printf("#");
} else {
printf("-");
}
}
printf("]\n\n");
}
int main() {
// 测试不同的文件路径
const char *test_paths[] = {
"/",
"/home",
"/tmp",
"/etc/passwd"
};
int num_paths = sizeof(test_paths) / sizeof(test_paths[0]);
printf("=== 磁盘空间监控工具 ===\n\n");
for (int i = 0; i < num_paths; i++) {
struct disk_usage usage;
if (get_disk_usage(test_paths[i], &usage) == 0) {
print_disk_usage(&usage);
} else {
printf("无法获取 %s 的磁盘信息\n\n", test_paths[i]);
}
}
return 0;
}
编译和运行说明
gcc -o fstatfs_example fstatfs_example.c
./fstatfs_example
注意事项
- 文件系统类型: 不同的文件系统类型有不同的魔数(magic number),可以通过
f_type
字段识别 - 权限要求: 通常只需要对文件有读权限即可调用此函数
- 空间计算:
f_bfree
: 所有用户都可用的空闲块数f_bavail
: 非超级用户可用的块数(通常更小)
- 移植性:
statfs
结构体在不同系统上可能有差异,如需高移植性可考虑使用statvfs
- 性能: 频繁调用此函数可能影响性能,建议缓存结果
这些示例展示了 fstatfs
函数的多种应用场景,从简单的空间信息获取到文件系统类型识别,再到实用的磁盘监控工具,帮助你全面理解这个函数的使用方法。