Go embed 介绍
Go embed是Go 1.16版本支持的一项功能,如果在这之前需要把资源文件内置到编译后的执行文件里面,需要采用第三方的库,比如go-bindata,需要在编译源代码之前,把需要内置的资源编译成Go代码,之后调用提供的接口获取文件。
Go 1.16版本的官方实现省去了多余的步骤,直接在代码里面调用指令,注解相应的变量:
import _ "embed"
//go:embed hello.txt
var s string
print(s)
变量的类型可以是string
/[]byte
/embed.FS
,前两个比较好理解,对应单个文件,embed.FS则是用于多个文件。
这个指令会选择性的忽略一些文件,比如image
是一个文件夹:
//go:embed image
var content embed.FS
上面代码文件夹子目录中_
和.
开头文件或文件夹会给忽略,下面代码则会包含对应的文件。
//go:embed image/*
var content embed.FS
io/fs
io/fs这个包是本次更新引入的,包括fs.FS
表示只读文件系统,还有表示文件和文件头信息的接口:
type FS interface {
Open(name string) (File, error)
}
type File interface {
Stat() (FileInfo, error)
Read([]byte) (int, error)
Close() error
}
type FileInfo interface {
Name() string
Size() int64
Mode() FileMode
ModTime() time.Time
IsDir() bool
Sys() interface{}
}
fs.FS
并没有注明遍历目录的方法,不过提供fs.Glob和fs.WalkDir两个方法可以查询的遍历文件,实现的原理是尝试将fs.FS
转换成fs.ReadDirFS类型或是fs.GlobFS类型。
fs.WalkDir
遍历文件,目录会优先出现,之后才是目录下面的文件,不过也与对应的接口实现有关,embed.FS
是有提前对文件进行排序,并且目录分隔符是/
,即使在Windows系统下也是/
,所以操作的时候需要统一使用filepath.ToSlash进行处理。
在部分涉及文件读写的地方,也加入了对应fs.FS
相关的函数,用来调用资源:
- template.ParseFS
- http.FS
文件系统到io.FS
接口
os.DirFS函数可以从现有的文件系统实现io.FS
接口:
var root:fs.FS = os.DirFS("public")
有了上面的函数,那么我们在开发程序的时候,如果只涉及到文件的读取,而不涉及文件写入,那么应该使用fs.FS
接口代替原先直接读写文件的方式,这样一来,就可以在内置资源和文件系统间来回切换。
zip.Reader 也实现了fs.FS
接口,打开一个zip文件,并且当成只读文件系统调用:
content,_ := zip.OpenReader("resources.zip")
http.Handle("/resources/", http.StripPrefix("/resources/", http.FileServer(http.FS(content))))