fstatfs系统调用及示例

fstatfs 函数详解

  1. 函数介绍

fstatfs 是 Linux 系统中用于获取文件系统统计信息的系统调用。可以把这个函数想象成一个”文件系统体检工具”——当你给它一个已打开的文件描述符时,它会告诉你这个文件所在文件系统的详细信息,比如总空间多大、已用多少、还剩多少、支持什么特性等等。

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

就像你去体检时医生会检查你的身高、体重、血压等指标一样,fstatfs 会检查文件系统的”健康状况”和”基本信息”。

  1. 函数原型
1
2
3
4
#include <sys/vfs.h>    /* 或者 #include <sys/statfs.h> */

int fstatfs(int fd, struct statfs *buf);

  1. 功能

fstatfs 函数用于获取与指定文件描述符相关的文件系统的统计信息。它填充一个 statfs 结构体,其中包含了文件系统的各种参数和状态信息。

  1. 参数
  • fd: 已打开的文件描述符(可以是任何类型的文件:普通文件、目录、设备等)

  • buf: 指向 struct statfs 结构体的指针,用于存储返回的文件系统信息

  1. 返回值
  • 成功: 返回 0

  • 失败: 返回 -1,并设置相应的 errno 错误码

常见错误码:

  • EBADF: fd 不是有效的文件描述符

  • EFAULT: buf 指针无效

  • EIO: I/O 错误

  • ENOSYS: 系统不支持此操作

  1. 相似函数或关联函数
  • statfs: 通过文件路径获取文件系统信息(需要文件路径而非文件描述符)

  • statvfs: POSIX 标准的文件系统信息获取函数(提供更标准化的接口)

  • fstatvfs: 通过文件描述符获取 POSIX 标准的文件系统信息

  • stat: 获取文件本身的详细信息(不是文件系统信息)

  1. struct statfs 结构体详解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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&#91;5]; /* 保留字段 */
};

  1. 示例代码

示例1:基础用法 - 查看文件系统空间信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#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:文件系统类型识别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#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&#91;] = {"/etc/passwd", "/proc/version", "/sys/kernel"};
int num_files = sizeof(test_files) / sizeof(test_files&#91;0]);

for (int i = 0; i < num_files; i++) {
printf("\n=== 检查文件: %s ===\n", test_files&#91;i]);

// 打开文件
fd = open(test_files&#91;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:磁盘空间监控工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/vfs.h>
#include <string.h>

// 磁盘使用情况结构体
struct disk_usage {
char path&#91;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&#91;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%% &#91;", 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&#91;] = {
"/",
"/home",
"/tmp",
"/etc/passwd"
};

int num_paths = sizeof(test_paths) / sizeof(test_paths&#91;0]);

printf("=== 磁盘空间监控工具 ===\n\n");

for (int i = 0; i < num_paths; i++) {
struct disk_usage usage;

if (get_disk_usage(test_paths&#91;i], &usage) == 0) {
print_disk_usage(&usage);
} else {
printf("无法获取 %s 的磁盘信息\n\n", test_paths&#91;i]);
}
}

return 0;
}

编译和运行说明

1
2
3
gcc -o fstatfs_example fstatfs_example.c
./fstatfs_example

注意事项

文件系统类型: 不同的文件系统类型有不同的魔数(magic number),可以通过 f_type 字段识别

权限要求: 通常只需要对文件有读权限即可调用此函数

空间计算:

  • f_bfree: 所有用户都可用的空闲块数

  • f_bavail: 非超级用户可用的块数(通常更小)

移植性: statfs 结构体在不同系统上可能有差异,如需高移植性可考虑使用 statvfs

性能: 频繁调用此函数可能影响性能,建议缓存结果

这些示例展示了 fstatfs 函数的多种应用场景,从简单的空间信息获取到文件系统类型识别,再到实用的磁盘监控工具,帮助你全面理解这个函数的使用方法。

fstatfs系统调用及示例-CSDN博客

data-ad-format="auto" data-full-width-responsive="true">