Go Embed
Go embed 实现将文件打包到Go程序中
参考链接:https://juejin.cn/post/7103539856805986334
Go是一门编译型语言,编译后生成的二进制文件可以直接在对应的操作系统直接运行,我们编译出来的程序一般都是一个二进制文件,但是在实际的使用过程中,除了二进制文件,我们还需要一些配置文件或者一些静态的文件,如Html,CSS,等文件。如果我们可以将这些文件在编译的时候,就一同打包到我们的二进制中,那是一件很每秒的事情,也能降低使用方的门槛~
Go在1.16中提供了go:embed
的功能,有了他,就可以实现将一些文件嵌入到我们的打包程序中。
牛刀小试
准备一个文件hello.txt,里面内容为 hello go:embed
项目的文件路径如下
- hello.txt
- hello_embed.go
- hello_embed_test.go
hello_embed.go
import (
_ "embed"
)
//go:embed hello.txt
var hello string
func ReadHelloTxt() string {
return hello
}
测试方法
import "testing"
func Test(t *testing.T) {
t.Log(ReadHelloTxt())
}
通过运行测试用例,控制台输出了hello.txt中的文本内容
=== RUN Test
hello_embed_test.go:6: hello go:embed
--- PASS: Test (0.00s)
PASS
ok gotest 0.124s
注意事项
1)//go:embed
文件名,注释后面不能加空格,否则失效,有的小伙伴喜欢在注释后面加一个空格,但是如果是在此处加的话,形如:// go:embed
这样会导致embed失效
2)我们需要导入embed的包才能使用,即 import _ "embed"
3)要读取的文件或者文件夹只能在当前目录或者当前目录的子目录,不能是其他目录,否则会执行报错~
go:embed 可以嵌入的内容&注意事项
1)对于单个文件,支持嵌入为字符串或者字节切片
2)对于多个文件,支持嵌入文件系统embed.FS
3)只能嵌入为 string,byte slice和embed.FS三种类型,这三种类型的别名或者类型命名都不可以
嵌入为字符串或者字节切片
//go:embed hello.txt
var hello string
//go:embed hello.txt
var helloRaw []byte
嵌入为embed.FS
文件系统
嵌入为文件系统,这个功能在嵌入为多个文件或者嵌入的是文件夹的时候,非常实用。
//go:embed hello.txt
var helloFS embed.FS
func ReadHelloFS() string {
data, _ := helloFS.ReadFile("hello.txt")
return string(data)
}
嵌入多个文件
新增hello_1.txt文件在我们项目中
- hello.txt
- hello_1.txt
- hello_embed.go
- hello_embed_test.go
嵌入多个文件的写法有很多,比如:
- 使用多个go:embed
//go:embed hello.txt
var hello string
//go:embed hello_1.txt
var hello1 string
- 使用文件系统
//go:embed hello.txt
//go:embed hello_1.txt
var hello embed.FS
func main() {
data, _ := helloFS.ReadFile("hello.txt")
fmt.Println(string(data))
data1, _ := helloFS.ReadFile("hello.txt")
fmt.Println(string(data1))
}
- 写到一行
//go:embed hello_1.txt hello.txt
var hello embed.FS
文件夹嵌入
在我们的项目中增加一个文件夹,并将刚才的文本文件放到文件夹中
cmd
- p
|- hello.txt
|- hello_1.txt
- hello_embed.go
- hello_embed_test.go
我们可以通过嵌入文件夹的形式将P文件夹中以及子文件夹全部嵌入到我们的项目中,这里使用的是相对路径
//go:embed p
var helloFS embed.FS
func main() {
data, _ := helloFS.ReadFile("p/hello.txt")
fmt.Println(string(data))
data1, _ := helloFS.ReadFile("p/hello.txt")
fmt.Println(string(data1))
}
模糊匹配
go:embed
指令中可以只写文件夹名称,次文件夹中除了.
或者_
开头的文件和文件夹都会嵌入到程序中,并且子文件夹也会被递归的嵌入,形成一个文件系统。
如果想嵌入.
或者_
开头的文件或者文件夹,我们可以通过使用*
,比如:go:embed p/*
,注意,*
不具有递归性,所以子文件夹下面的.
或者_
不会被嵌入
文件过滤
go:embed
还支持文件前缀过滤的功能,比如我们想嵌入所有拓展名是.txt
的文件到程序中,我们可以这样写
//go:embed p
var helloFS embed.FS
func main() {
data, _ := helloFS.ReadFile("p/hello.txt")
fmt.Println(string(data))
data1, _ := helloFS.ReadFile("p/hello.txt")
fmt.Println(string(data1))
}