Go embed 静态资源编译

编写工具的时候往往需要依赖一些配置文件、模板文件等静态资源,但编译成可执行文件后仍然需要读取相关资源,这样就导致本身是为了方便的二进制文件还需要一堆配置模板文件才能正常运行,反而不太方便了。

go 1.16 新增了 //go:embed 指令,可以使用 go doc embed 查看说明文档。下面举一个读取配置文件、模板的案例。

导入 embed,读取配置文件使用 viper。

1
2
3
4
5
6
7
import (
"bytes"
_ "embed"
"fmt"

"github.com/spf13/viper"
)

使用 embed 包嵌入配置文件,这里的 //go:embed config.yaml 并不是注释。

1
2
3
4
5
//go:embed config.yaml
var embeddedConfig []byte

//go:embed tem.yaml
var embeddedTemplate []byte

定义配置文件结构体。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type API struct {
Ks string `yaml:"KS"`
}

type SET struct {
User string `yaml:"User"`
TempDir string `yaml:"TempDir"`
DescDir string `yaml:"DescDir"`
}

type Config struct {
Api API
Set SET
}

编写一个函数用来解析文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func ReadConfig() (*Config, error) {
viper.SetConfigType("yaml")
err := viper.ReadConfig(bytes.NewBuffer(embeddedConfig))
if err != nil {
return nil, fmt.Errorf("error reading embedded config: %w", err)
}

var config Config
err = viper.Unmarshal(&config)
if err != nil {
return nil, fmt.Errorf("error unmarshaling config: %w", err)
}
return &config, nil
}

读取扫描模板

1
2
3
4
5
6
7
// 读取扫描模板
func ReadTemplateContent() (string, error) {
if len(embeddedTemplate) == 0 {
return "", fmt.Errorf("扫描模板文件为空或未嵌入")
}
return string(embeddedTemplate), nil
}

此时使用 ReadConfig 获取 Config 结构体,使用 ReadTemplateContent 读取 tem.yaml 的文件内容。编译后的二进制文件,就可以不依赖静态文件也可以运行。