0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Go文件系统的概念

Linux爱好者 来源:Linux爱好者 作者:Linux爱好者 2022-10-17 10:05 次阅读

什么神奇问题 ?

Go 在文件 IO 的场景有个神奇的事情。打开一个文件的时候,返回的竟然不是 interface ,而是一个 os.File 结构体的指针。

funcOpen(namestring)(*File,error){
returnOpenFile(name,O_RDONLY,0)
}

划重点:这个意味着,Go 的文件系统的概念和 OS 的文件系统的概念直接关联起来。你必须传入一个文件路径,并且必须真的要去打开一个操作系统的文件。

不用接口,而是跟具体类型强相关的话,会导致后续的扩展性不好。比如,全都是 os 包的使用,那么将操作强绑定在 OS 文件系统上。

最常见的,在单测的时候用的这种方式的话,就真的要在操作系统上打开文件做操作。Go 的设计者对此一直耿耿于怀,但是也很无奈。因为用户已经用上了,Go 的承诺是往前兼容,直接修改原有语义和接口肯定不行。

怎么办

Go 1.16 给了我们答案。Go 给了我们一个 io.FS 的封装。Go 的意图是在自己的语言层面再做一层 FS 的抽象,这样就能和 OS 的 FS 解耦开来。io.FS 可以是任何奇形怪状的 FS ,只要你实现了规定好的 FS 接口。下一步来看下 Go 1.16 带来的几个核心改动。

有人说 Go 都 1.19 了,还看 1.16 ?

因为 Go 的 io/fs 是在 Go 1.16 引入的。在 io 方面有比较大的一个变化。

Go 1.16 关于 io 有哪些改变 ?

新增了一个 io/fs 的包,抽象了一个 FS 出来。

embed 的 package 用了这个抽象。

规整 io/ioutil 里面的内容。

接下来我们一个个看下。

io.FS 的抽象

1Go 为什么要抽象 FS ?

前面已经提到,Go 的文件系统的概念和 OS 的文件系统的概念直接关联起来。这个给扩展性带来了不方便。最重要的,Go 已经发现有和 OS 不同的文件系统的需求了,就是 embed FS 。

embed 是 Go 提供的一个打包文件到二进制的功能,也是类似文件系统的一种需求。但是却不是直接位于 OS 上的文件系统(vfs 那套东西)。

所以在 Go 1.16 顺势就一起上了。引入了 io.FS 的定义,并且 embed 就直接用上了这层抽象。

![[fs 封装层次.png]]

2来看下 FS 接口的定义

Go 的实现者们很强,推荐的是小接口。也就是最小化、原子化的接口语义。从 io/fs 的定义就能看到很强的功力。

//文件系统的接口
typeFSinterface{
Open(namestring)(File,error)
}

//文件的接口
typeFileinterface{
Stat()(FileInfo,error)
Read([]byte)(int,error)
Close()error
}

这,就是最简单的 FS 。 这个就是文件系统极简的样子,只需要有一个 Open 方法,返回一个文件即可。

也就是说,Go 理解的文件系统,只要能实现一个 Open 方法,返回一个 File 的 interface ,这个 File 只需要实现 Stat,Read,Close 方法即可。

有没有发现,OS 的 FS 已经满足了条件。所以,Go 的 FS 可以是 OS 的 FS ,自然也可以是其他的实现。

Go 在此 io.FS 的基础上,再去扩展接口,增加文件系统的功能。比如,加个 ReadDir 就是一个有读目录的文件系统 ReadDirFS :

typeReadDirFSinterface{
FS
//读目录
ReadDir(namestring)([]DirEntry,error)
}

加个 Glob 方法,就成为一个具备路径通配符查询的文件系统:

typeGlobFSinterface{
FS
//路径通配符的功能
Glob(patternstring)([]string,error)
}

加个 Stat ,就变成一个路径查询的文件系统:

typeStatFSinterface{
FS
//查询某个路径的文件信息
Stat(namestring)(FileInfo,error)
}

这些非常经典的文件系统的定义 Go 在 io/fs 里面已经做好了。

3io.FS 怎么使用呢?

我们的目标是实现一个 Go 的 FS ,这个定义已经在 io.FS 有了。我们只需要写一个结构体,实现它的方法,那么你就可以说这是一个 FS 了。

这里其实就可以有非常多的想象空间,比如,可以是 OS 的 FS,也可以是 memory FS ,hash FS 等等。网上有不少例子。但其实标准库已经有一个最好的例子,那就是 embed FS 。

我们来看下 embed 怎么实现一个内嵌的文件系统。embed 的实现在 embed/embed.go 这个文件中,非常精简。

首先,在 embed package 里定义了一个结构体 FS ,这个结构体将是 io.FS 的具体实现。

//作为具体FS的实现
typeFSstruct{
files*[]file
}

//代表一个内嵌文件
typefilestruct{
namestring
datastring//文件的数据全在内存里
hash[16]byte//truncatedSHA256hash
}

embed 里面的 FS 结构体只需要实现 Open 这个方法即可:

//Open的具体实现
func(fFS)Open(namestring)(fs.File,error){
//通过名字匹配查找到file对象
file:=f.lookup(name)
//如果没找到
iffile==nil{
returnnil,&fs.PathError{Op:"open",Path:name,Err:fs.ErrNotExist}
}
//如果是目录结构
iffile.IsDir(){
return&openDir{file,f.readDir(name),0},nil
}
//找到了就封装成openFile结构体
return&openFile{file,0},nil
}

上面的 Open ,如果是文件的化,返回的是一个 openFile 的结构体 ,作为 io.File 接口的具体实现:

//代表一个文件的实现
typeopenFilestruct{
f*file//thefileitself
offsetint64//currentreadoffset
}
func(f*openFile)Close()error{returnnil}
func(f*openFile)Stat()(fs.FileInfo,error){returnf.f,nil}
func(f*openFile)Read(b[]byte)(int,error){
//判断偏移是否符合预期
iff.offset>=int64(len(f.f.data)){
return0,io.EOF
}
iff.offset< 0 {
        return 0, &fs.PathError{Op: "read", Path: f.f.name, Err: fs.ErrInvalid}
    }
    // 从内存拷贝数据
    n := copy(b, f.f.data[f.offset:])
    f.offset += int64(n)
    return n, nil
}

如上,只需要实现 Read,Stat,Close 方法即可。这就是一个完整的、Go 层面的 FS 的实现。

你可以如下使用 embed 文件系统:

//go:embedhello.txt
varfembed.FS

funcmain(){
//打开文件
file,err:=f.Open("hello.txt")
//...
//读文件
n,err=file.Read(/*buffer*/)
}

上面的例子,编译的时候会把当前目录下的一个 hello.txt 文件打包到二进制文件。程序启动的时候可以把它读出来。

注意:f 这个变量,编译器会安排填充好。进程启动时它是有值的。

Go 1.16 关于 IO 其他的改动

除了上面提到的 io/fs 和 embed fs ,Go 对之前的 io 的一些结构也做了更准确的调整分类。把之前大杂烩的 io/ioutil 里面的东西拆出来了。移到对应的 io 包和 os 包。为了兼容性,ioutil 包并没有直接删除,而是导入。比如:

Discard 移到了 io 库实现

ReadAll 移到了 io 库实现

NopCloser 移到了 io 库实现

ReadFile 移到 os 库实现

WriteFile 移到 os 库实现

基本上 ioutil 这个 package 是被掏空了。Go 1.16 只是为了兼容性还没删。

Go 的 FS 封装有啥用呢 ?

好处其实很多,最明显的两个:

单测方便了。

有类似 embed FS 这种非 OS 文件系统的需求,可以有方法扩展了。

总结

Go 在自己的层面封装出一个 io.FS 的抽象,意图和 OS 的 FS 解耦。这样可以给程序员带来更多的想象空间 ;

embed FS 具备典型的 FS 的界面,但是它并不是直接位于 OS 的文件系统。所以它非常适合作为首个用 io.FS 的实践;

以后尽量用 io.FS 来管理的文件,这样可以做到和 OS 解耦,方便做单测;

ioutil 可以少用,它的功能已经被移到更明确的 package 里实现了;

审核编辑:彭静
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 接口
    +关注

    关注

    33

    文章

    7639

    浏览量

    148485
  • 操作系统
    +关注

    关注

    37

    文章

    6284

    浏览量

    121876
  • 文件系统
    +关注

    关注

    0

    文章

    273

    浏览量

    19676

原文标题:Go 眼中的文件系统是什么? io.FS

文章出处:【微信号:LinuxHub,微信公众号:Linux爱好者】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Go文件系统概念及实现

    Go文件 IO 的场景有个神奇的事情。打开一个文件的时候,返回的竟然不是 interface ,而是一个 os.File 结构体的指针。
    发表于 10-17 10:00 464次阅读

    Linux文件系统课程

    本章学习目标理解什么是文件系统了解文件系统工作原理理解Fedora Core Linux文件系统的结构掌握Fedora Core Linux文件系统的类型、权限和修改方法掌握如何安装、
    发表于 04-10 17:07 0次下载

    NTFS文件系统,NTFS文件系统是什么意思

    NTFS文件系统,NTFS文件系统是什么意思 NTFS是Windows NT以及之后的Windows 2000、Windows XP、Windows Server 2003、Windows Server 2008
    发表于 03-29 10:38 5678次阅读

    XfS文件系统,XfS文件系统是什么意思

    XfS文件系统,XfS文件系统是什么意思 XfS文件系统是SGI开发的高级日志文件系统,XFS极具伸缩性,非常健壮。所幸的是SGI将其移植到了Lin
    发表于 03-29 10:39 4076次阅读

    Linux根文件系统简介

    Linux根文件系统简介 什么是根文件   根文件系统首先是一种文件系统,但是相对于普通的文件系统,它的特殊之处在于,它是内核启动时所m
    发表于 04-21 17:01 5027次阅读

    FatFs文件系统使用

    STM系列FatFs文件系统使用文件,希望对大家有帮助。
    发表于 11-06 18:10 8次下载

    嵌入式系统文件系统比较

    Linux支持多种文件系统,包括ext2、ext3、vfat、ntfs、iso9660、jffs、romfs和nfs等,为了对各类文件系统 进行统一管理,Linux引入了虚拟文件系统VFS
    发表于 11-01 15:35 1次下载

    文件系统是什么?浅谈EXT文件系统历史

    在先前关于Linux文件系统的文章中,我很想去深入地讨论更多EXT文件系统的特性的信息。所以,首先让我们来回答这个问题:什么是文件系统?一个文件系统应该遵循以下特点。
    发表于 06-28 09:03 5432次阅读
    <b class='flag-5'>文件系统</b>是什么?浅谈EXT<b class='flag-5'>文件系统</b>历史

    linux文件系统中的虚拟文件系统设计详解

    Linux 中允许众多不同的文件系统共存,如 ext2, ext3, vfat 等。通过使用同一套文件 I/O 系统 调用即可对 Linux 中的任意文件进行操作而无需考虑其所在的具体
    发表于 04-02 14:37 1583次阅读
    linux<b class='flag-5'>文件系统</b>中的虚拟<b class='flag-5'>文件系统</b>设计详解

    一文解读文件系统的作用性(二)

    我就尝试着来模拟一次文件系统的演进过程,于是,我们来到了那一天,那天之前,人们还没有文件系统概念。 友情提示 : 下面将在荒诞的场景下演进人类合理的诉求 神说,要有光,于是,光照大地 神说,要有风,于是,风动四方 神说,人类要
    的头像 发表于 09-21 14:17 1552次阅读
    一文解读<b class='flag-5'>文件系统</b>的作用性(二)

    如何去自制文件系统?开发文件系统为什么难?

    我们先从什么是文件系统讲起,简单介绍一些探索文件系统的基础知识。
    的头像 发表于 06-11 16:27 3152次阅读
    如何去自制<b class='flag-5'>文件系统</b>?开发<b class='flag-5'>文件系统</b>为什么难?

    嵌入式Linux开发之文件系统目录结构介绍

    中。一、与windows区别Linux不像windows有盘符的概念,只有一个根目录概念,所有文件系统(硬盘、U盘、CDROM、网络文件系统)都以一个子目录挂根目录下某一子目录下。在L
    发表于 11-01 16:31 3次下载
    嵌入式Linux开发之<b class='flag-5'>文件系统</b>目录结构介绍

    FATFS文件系统详解

    一、文件系统负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。即在磁盘上组织文件
    发表于 11-29 09:51 29次下载
    FATFS<b class='flag-5'>文件系统</b>详解

    什么是分布式文件系统

    我们无时无刻不在使用文件系统,进行开发时在使用文件系统,浏览网页时在使用文件系统,玩手机时也在使用文件系统
    的头像 发表于 03-10 16:21 3659次阅读

    Linux的文件系统特点

    Linux的文件系统特点 文件系统要有严格的组织形式,使得文件能够以块为单位进行存储。 文件系统中也要有索引区,用来方便查找一个文件分成的多
    的头像 发表于 11-09 14:48 482次阅读
    Linux的<b class='flag-5'>文件系统</b>特点