Administrator
发布于 2024-02-26 / 7 阅读
0
0

文件打洞和稀疏文件

文件打洞和稀疏文件

稀疏文件 稀疏文件

稀疏文件是一种文件,其中大部分内容是空的(或者说是零填充的),但文件系统仍然为其分配了存储空间,文件大,实际占用磁盘空间少,我们 使用lseek或truncate到一个固定位置生成的“空洞文件”是不会占据真正的磁盘空间


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

int main() {
    int fd;
    off_t offset = 1024 * 1024 * 1024; // 1 GB
    char buf[1]; // Writing a single byte

    // Open a file
    fd = open("sparse_file.txt", O_WRONLY | O_CREAT, 0666);
    if (fd == -1) {
        perror("open");
        return 1;
    }

	// 更新 offest, 增大size
    if (lseek(fd, offset - 1, SEEK_SET) == -1) {
        perror("lseek");
        close(fd);
        return 1;
    }
    // Write a single byte at the offset position
    if (write(fd, buf, 1) != 1) {
        perror("write");
        close(fd);
        return 1;
    }

    // Close the file
    close(fd);

    printf("Sparse file created successfully.\n");
    return 0;
}


#写入后,实际磁盘 占用只有4k(8个block) ,但是size为 1073741824
root@ubuntu:/home# gcc test.c -o test && ./test
Sparse file created successfully.
root@ubuntu:/home# ls -sl sparse_file.txt
4 -rw-r--r-- 1 root root 1073741824 Feb 26 07:15 sparse_file.txt

root@ubuntu:/home# stat sparse_file.txt
  File: sparse_file.txt
  Size: 1073741824	Blocks: 8          IO Block: 4096   regular file
Device: 801h/2049d	Inode: 1102149     Links: 1

文件打洞 文件打洞

上边例子中稀疏文件,是通过在空文件中的某个偏移量写入了1个字节得到的。一个文件开始并非稀疏的,它已经占用了若干的磁盘空间, 可能某段范围的内容已经失效了,想把这段失效的文件部分所占用的磁盘空间还给文件系统,我们为了减小文件所占用的磁盘空间,就只能通过文件打洞 (Hole Punching)的方式将非稀疏文件转为稀疏文件, 主动释放一段文件所占的物理空间

要想达到该效果,linux 系统上有专门的函数实现 fallocate

fallocate用于预分配块到文件。对于支持fallocate系统调用的文件系统,这是通过分配块并将它们标记为未初始化的,从而快速完成的,不需要IO到数据块。这比用0填充文件要快得多。

在Linux内核v2.6.31的情况下,fallocate系统调用由btrfs、ext4、ocfs2和xfs filesystems支持。 fallocate返回的退出代码在成功时是0,而失败则是1。

```

1

2

3

```

```hljs c

int fallocate(int fd, int mode, off_t offset, off_t len);

mode为0,此时会将文件的[offset, offset+len)区域的内容写为0

mode为 FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE [offset, offset+len)区域中的块就会被“打洞” 回收,减少系统占用

```

假如现在有个 42k大小的文件,有数据的


root@ubuntu:/home# ll -s -h hole
44K -rw-r--r-- 1 root root 42K Feb 26 07:40 hole

接下来我用 fallocate 回收 hole 文件 在 \[4096 ,8192\] 的空间


#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
// 注意在CentOS 7中还需要包含linux/falloc.h:
#include <linux/falloc.h>
#include <sys/stat.h>
#include <assert.h>

int main()
{
    int ret;
    int fd;
    fd = open("./hole", O_RDWR|O_CREAT, 0755);
    assert(fd != -1);
    // 4096 ~ 8192
    ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, 4096,8192);
    assert(ret == 0);
    close(fd);
    return 0;
}

执行程序并看下文件大小, 可以看到, size 并没有变化,还是42k, 但是 磁盘空间变化了


root@ubuntu:/home# ll -sh hole
40K -rw-r--r-- 1 root root 42K Feb 26 07:42 hole


评论