You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux环境下如何用C语言快速创建无空洞大文件?

嘿,这个问题我太有共鸣了!当年fallocate秒建8GB大文件的速度确实惊艳,我来给你捋清楚这里面的门道~

先搞懂当年的效果到底是什么

你回忆里的“无空洞文件”,其实是内核直接预分配磁盘块并初始化为零的文件——这类文件用ls -lh和du -h看大小完全一致,没有“磁盘占用远小于文件标称大小”的空洞情况,而且因为是内核级操作,速度快到离谱。

现在你觉得创建的文件有洞,大概率是混淆了“预分配零块”和“空洞文件”:空洞文件是通过lseek跳着写出来的,磁盘上根本没有对应中间区域的块;而fallocate预分配的文件,所有块都实实在在占了磁盘空间,只是内容是零,本质上不是空洞。

C语言实现当年效果的两种方式

方式1:直接调用Linux专属的fallocate()系统调用(最快)

这个就是当年fallocate工具底层用的方法,从Linux 2.6.23内核开始就存在,至今完全可用。只要调用时不指定FALLOC_FL_KEEP_SIZE标志,内核就会自动扩展文件大小、预分配所有需要的磁盘块并填零,全程在内核态完成,速度拉满。

示例代码:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    const char* filename = "fast_bigfile";
    // 创建/截断文件为读写模式
    int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("Failed to open file");
        return 1;
    }

    off_t target_size = 8LL * 1024 * 1024 * 1024; // 8GB
    // 0表示无额外标志,等价于FALLOC_FL_FALLOCATE
    int ret = fallocate(fd, 0, 0, target_size);
    if (ret == -1) {
        perror("Failed to allocate file space");
        close(fd);
        return 1;
    }

    close(fd);
    printf("8GB file created successfully (no holes, kernel-level zeroed)\n");
    return 0;
}

方式2:用POSIX标准的posix_fallocate()(更便携)

如果需要兼顾其他类Unix系统,可以用这个POSIX标准函数。在Linux上它其实还是底层调用fallocate()实现,效果和速度跟上面差不多;但在BSD等系统上,可能会用用户态写零的方式,速度会慢一些。

示例代码:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

int main() {
    const char* filename = "portable_bigfile";
    int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("Failed to open file");
        return 1;
    }

    off_t target_size = 8LL * 1024 * 1024 * 1024; // 8GB
    int ret = posix_fallocate(fd, 0, target_size);
    if (ret != 0) {
        errno = ret;
        perror("Failed to allocate file space (POSIX)");
        close(fd);
        return 1;
    }

    close(fd);
    printf("8GB file created successfully (POSIX compliant, no holes)\n");
    return 0;
}
关于内核调用的变化

fallocate()系统调用确实是Linux专属的,而且从诞生至今没有被废弃——只是后来新增了FALLOC_FL_KEEP_SIZE等标志,让工具更灵活。比如现在如果用fallocate -k -l 8G file,就会只预分配空间但不改变文件大小,这时候读超过原文件大小的部分会返回EOF,容易被误以为是空洞,但其实磁盘空间已经被占了。

当年你用的fallocate应该是默认调用了无额外标志的fallocate(),也就是直接扩展文件大小并预分配填零,这个逻辑现在依然可以通过代码实现,完全没问题。

验证是否真的无空洞

创建完文件后,可以用这两个命令确认:

  • ls -lh filename 和 du -h filename:如果两个输出的大小一致,说明没有空洞(磁盘确实占了对应空间)
  • filefrag -v filename:查看文件的磁盘块分布,如果没有“hole”标记,就是真正的无空洞文件

内容的提问来源于stack exchange,提问作者Nick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 16:02:44