空洞文件
在一般文件的情况下,对于普通文件来说,文件数据的理论大小 == 在块设备上实际占用的空间大小。
但是空洞文件却不是这样的,对于空洞文件来说,
文件数据的理论大小 > 在块设备上实际占用的空间大小。
空洞文件的意义
打个比方
我承诺给你一亩地,但是你又不是马上就要用满这一亩地,是一点一点来占用的,如果我现在一下子就把一亩地全部给你,但是你要花费很久时间才会把地全用上,在你占满之前,一直有相当部分的空间被闲置不用,显然非常浪费空间资源。
解决办法是,我先承诺说给你一亩地,但是这一亩地先不全部给你,你搬一部分东西过来时,我给你一部分空间,按照这样的方式,直到把1亩地的空间全部给你,在你没有用满一亩地之前,其它的空间我就可以用作其他用处。
迅雷等下载文件
比如下载一个1M大小的文件,文件肯定是要花费相当长的时间才能下载完成,如果我直接就开辟一个实际占用1M空间的普通文件来放数据的话,在实际下载完数据之前,未装满数据的空间都被闲置,会很浪费空间。
解决办法就是开辟一个1M大小的空洞文件,空洞文件的理论大小是1M,但是并没有在块设备上实际给你分配1M的物理空间,
而是在下载过程中,每下载一部分数据,再实际开辟一部分空间给你,直到整个文件下完位置。
制作空洞文件
truncate、ftrucate制作
文件截短长度 > 文件长度时,多余的部分就是空洞。
代码演示:
我们先创建一个文件:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int fd = 0;
fd = open("hole_file.txt",O_RDWR|O_CREAT,0777);
if(-1 == fd)
{
printf("open fail\n");
exit(-1);
}
return 0;
}
执行结果为:
我们可以看到创建成功大小为0。
我们现在进行截断,把问hole_file.txt文件大小设置为8000:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int fd = 0;
fd = open("hole_file.txt",O_RDWR|O_CREAT,0777);
if(-1 == fd)
{
printf("open fail\n");
exit(-1);
}
ftruncate(fd,8000);
return 0;
}
执行结果为:
我们可以看到现在文件的理论大小已经修改为8000
我们查看以下命令查看实际的文件在块设备上占用的大小:
du命令:查看文件在块设备上,实际占用的物理空间。
我们可以看到实际在磁盘上所占用的空间大小为0
ls查看到的只是文件的理论大小,但是空洞部分并不占用实际物理存储空间。我们打开查看一下空洞文件:
这种表示是空洞文件。
我们用二进制查看里面都是0
lseek制作
将文件读写位置调整到文件尾部之后,然后写点数据,中间空出的部分就是空洞。
代码演示:
我们先把刚才的hole_file.txt 文件删除了
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int fd = 0;
fd = open("hole_file.txt",O_RDWR|O_CREAT,0777);
if(-1 == fd)
{
printf("open fail\n");
exit(-1);
}
lseek(fd,8000,SEEK_SET);
write(fd,"hello",5);
return 0;
}
执行结果为:
我们可以看到文件理论大小为8005
实际大小为:
这里的4表示4k 就是4096个字节,是用来存放hello的,空洞部分不占用实际空间,块设备在分配空间的时候,如果根据需要的字节来分配的话效率不高,所以按照块来存储,效率比较高,最开始也会分配4块,这4块存储的就是hello,当把4块存储满了之后再单独开辟块进行存储。所以空洞部分还是没有占用实际的存储空间。