fallocate - 预分配文件空间
1. 函数介绍
fallocate 是 Linux 系统调用,用于为文件预分配磁盘空间。你可以把它想象成”预订”磁盘空间,就像你在餐厅预订座位一样——你告诉系统你需要多少空间,系统就为你预留出来,但此时还没有实际写入数据。
data-ad-format="fluid"
data-ad-layout-key="-7k+ex-4a-9w+4a">
这个函数的主要优势是:
提高文件系统性能:避免文件碎片
确保文件有足够空间:防止写入时空间不足
快速操作:比实际写入数据更快
2. 函数原型
1 2 3 4
| #include <fcntl.h>
int fallocate(int fd, int mode, off_t offset, off_t len);
|
3. 功能
为文件预分配指定范围的磁盘空间,而不需要实际写入数据。这可以优化文件系统的存储布局,提高I/O性能。
4. 参数
- int fd: 文件描述符,通过 open() 函数获得
int mode: 操作模式
0: 默认模式,分配空间
FALLOC_FL_PUNCH_HOLE: 创建空洞(释放空间)
FALLOC_FL_COLLAPSE_RANGE: 折叠范围
FALLOC_FL_ZERO_RANGE: 清零范围
off_t offset: 文件中的起始偏移量(字节)
off_t len: 要分配的长度(字节)
5. 返回值
成功时返回 0
失败时返回 -1,并设置 errno
6. 相似函数,或关联函数
7. 示例代码
示例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
| #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h>
int main() { int fd; int ret; // 创建一个新文件用于测试 fd = open("test_file.dat", O_CREAT | O_WRONLY | O_TRUNC, 0644); if (fd == -1) { perror("打开文件失败"); exit(EXIT_FAILURE); } printf("文件创建成功,文件描述符: %d\n", fd); // 预分配10MB的空间 ret = fallocate(fd, 0, 0, 10 * 1024 * 1024); if (ret == -1) { if (errno == EOPNOTSUPP) { printf("警告: 当前文件系统不支持 fallocate\n"); } else { perror("fallocate 调用失败"); } close(fd); exit(EXIT_FAILURE); } printf("成功预分配10MB空间\n"); // 关闭文件 close(fd); printf("文件已关闭\n"); 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
| #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h>
int main() { int fd; int ret; char data[] = "Hello, World!"; // 创建一个新文件 fd = open("sparse_file.dat", O_CREAT | O_WRONLY | O_TRUNC, 0644); if (fd == -1) { perror("打开文件失败"); exit(EXIT_FAILURE); } printf("创建文件,文件描述符: %d\n", fd); // 先写入一些数据在文件开头 if (write(fd, data, strlen(data)) == -1) { perror("写入数据失败"); close(fd); exit(EXIT_FAILURE); } printf("已在文件开头写入: %s\n", data); // 预分配10MB空间在1MB偏移处(创建空洞) ret = fallocate(fd, 0, 1024 * 1024, 10 * 1024 * 1024); if (ret == -1) { perror("fallocate 调用失败"); close(fd); exit(EXIT_FAILURE); } printf("在1MB偏移处预分配了10MB空间\n"); printf("此时文件大小约为11MB,但实际占用磁盘空间很小\n"); // 关闭文件 close(fd); printf("文件已关闭\n"); return 0; }
|
示例3:使用PUNCH_HOLE模式释放文件中间部分的空间
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
| #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h>
int main() { int fd; int ret; char data[1024]; // 创建测试文件并填充数据 fd = open("punch_hole_test.dat", O_CREAT | O_WRONLY | O_TRUNC, 0644); if (fd == -1) { perror("打开文件失败"); exit(EXIT_FAILURE); } printf("创建测试文件\n"); // 填充1MB数据 memset(data, 'A', sizeof(data)); for (int i = 0; i < 1024; i++) { if (write(fd, data, sizeof(data)) == -1) { perror("写入数据失败"); close(fd); exit(EXIT_FAILURE); } } printf("已写入1MB数据\n"); // 使用PUNCH_HOLE模式释放中间512KB的空间 // 注意:PUNCH_HOLE需要与FALLOC_FL_KEEP_SIZE一起使用 ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 256 * 1024, 512 * 1024); if (ret == -1) { if (errno == EOPNOTSUPP) { printf("当前文件系统不支持 PUNCH_HOLE 操作\n"); } else { perror("fallocate PUNCH_HOLE 操作失败"); } } else { printf("成功在文件中间创建了512KB的空洞\n"); printf("这部分空间已被释放,但文件大小保持不变\n"); } // 关闭文件 close(fd); printf("文件已关闭\n"); return 0; }
|
总结
fallocate 是一个非常有用的系统调用,特别适用于以下场景:
数据库系统预分配文件空间
大文件写入前的空间预留
虚拟机磁盘映像创建
需要避免文件碎片的高性能应用
记住,不是所有文件系统都支持所有模式,使用时需要检查返回值并做好错误处理。