• Golang 和稀疏文件


    点击上方蓝色“飞雪无情”关注我的公众号,设个星标,第一时间看文章

    在操作系统中,有一种特殊的文件,看着很大,但是实际占用磁盘的空间却很少,这种文件就是稀疏文件。

    这种文件的原理其实就是标记文件字节的内容为空(可以理解为NULL,但不是0),为空的内容不会真实的占用磁盘空间,所以也称为打洞,就像就一张纸片(文件)上打了一个个洞,这些洞没有存储数据,所以不占用空间。

    生成一个稀疏文件

    当知道了稀疏文件的原理后,就很容易的生成一个稀疏文件了。下面我使用Go语言生成一个1GB大小的稀疏文件,但是它的实际磁盘占用空间为0。

    1. func main() {
    2.    sparseFile, err := os.Create("sparse_file")
    3.    if err != nil {
    4.       log.Fatalln(err)
    5.    }
    6.    sparseFile.Truncate(1 << 30)
    7.    sparseFile.Close()
    8. }

    使用 Truncate 方法设置文件的大小,然后直接Close退出,就可以得到一个稀疏文件。

    1. ➜  hello ls -ls sparse_file 
    2. 0 -rw-r--r-- 1073741824 Aug 22 22:19 sparse_file

    通过 ls -ls 命令,可以看下这个文件的基本信息。注意这里要留意第一个数字 0 表示该文件实际占用的磁盘空间大小,是0字节。 1073741824 表示该文件的大小,是1GB。
    看,对吧,一个1GB大小的文件,实际占用才0字节。

    除了 ls -ls 命令,还有 du 命令可以查看占用的实际大小。

    1. ➜  hello du sparse_file 
    2. 0       sparse_file

    写入一些字节的稀疏文件

    我们也可以创建已经写入一些字节的稀疏文件,这个使用,对于打洞的内容,使用 Seek 方法跳过即可。

    1. func main() {
    2.    sparseFile, err := os.Create("sparse_file")
    3.    if err != nil {
    4.       log.Fatalln(err)
    5.    }
    6.    sparseFile.Truncate(1 << 30)
    7.    sparseFile.Write([]byte{0x01})
    8.    sparseFile.Seek(1<<30-10)
    9.    sparseFile.Write([]byte{0x02})
    10.    sparseFile.Close()
    11. }

    以上代码同样创建了1GB大小的稀疏文件,但是只有第1个字节和最后1个字节写了内容。 Seek 是一个很好的方法,他可以让你跳来跳去,在特定的位置写入你想写入的内容,并且保持稀疏文件的特性。

    哪些系统支持稀疏文件

    其实现在我们用到的大多数文件系统都支持稀疏文件,比如Windows的NTFS、Linux的Ext4、MacOS的APFS都支持稀疏文件。

    这里需要注意的是苹果从2016年宣布的APFS文件系统,如果你的是早期的苹果电脑,可能会不支持。

    以类Unix系统为例,即使你不用Go语言,也可以很轻松的创建一个稀疏文件,比如:

    ➜  dd of=sparse-file bs=1k seek=5120 count=0

    以上就创建了一个5M的文件,但是实际的磁盘占用空间为0。

    稀疏文件的应用

    了解了稀疏文件的特点,你应该可以想出一些稀疏文件的使用场景了。

    没错,就是那些将来是大文件,但是现在还没那么大的文件。对于这类场景,稀疏文件再适合不过,甚至你可以创建比你的磁盘还大的稀疏文件。

    比如磁盘镜像,这在虚拟机中很常用。我们想创建一个500G大小的磁盘,但是现在又不想它占用这么多空间,用多少就占用多少,那么把稀疏文件作为磁盘镜像尤其合适。

    比如内存快照,这类在虚拟机中用的比较多。一个内存10GB的虚拟机,我们想把内存数据做个快照,但是内存里的数据是不固定的,但是最大只有10GB。

    这时候就可以创建一个10GB的稀疏文件,把虚拟机的内存数据写到这个稀疏文件即可,在写入数据的时候,只写非零的字节数据,这样就可以减少磁盘占用。

    这里和Golang的结合可以参考syscall.Mmap系统调用,你可以自己试试,这里不再举例。

    func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error)

    小结

    稀疏文件在很多特定的场景都很好用,但是它也不是完美无缺的。比如在你重写文件的时候,磁盘可能「突然」会满;复制、打包、远程传输的时候可能会丢失稀疏文件的特性。

    但是不管怎么说,这是一个很好的文件特定,尤其是在磁盘镜像、快照、日志等场景,尤其合适,善于使用它们,会有意想不到的收获。

    f06bcc2265efe8391fa858dbdc9ed85b.png

    扫码关注

    分享、点赞、在看就是最大的支持

  • 相关阅读:
    我的 React 最佳实践
    红帽Linux的安装和部署
    【JUC2022】第一章 CompletableFuture
    docker 基本操作
    【Android笔记25】Android中的动画效果之逐帧动画
    MongoDB入门与实战-第四章-SpringBoot集成MongoDB
    极智开发 | CUDA线程模型与全局索引计算方式
    【C++笔记】第十三篇 面向对象及三大特性
    框架的重要组成
    数据清洗:数据挖掘的前期准备工作
  • 原文地址:https://blog.csdn.net/flysnow_org/article/details/126552675