Contents

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

嵌入多个文件的写法有很多,比如:

  1. 使用多个go:embed
//go:embed hello.txt
var hello string

//go:embed hello_1.txt
var hello1 string
  1. 使用文件系统
//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))
}
  1. 写到一行
//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))
}