Skip to content

go embed

embed 是 Go 1.16 引入的一项功能,用于将文件或文件夹嵌入到 Go 程序中。在编译时,Go 编译器会把这些文件的内容嵌入到生成的二进制文件中,这样就可以在不依赖外部文件的情况下运行应用程序。常用于嵌入配置文件、HTML 模板、静态资源等。

1. 使用 embed 嵌入单个文件

要使用 embed,需要在 Go 文件中使用 //go:embed 注释来指定要嵌入的文件,然后通过变量来访问这些文件的内容。

示例:嵌入一个单独的 config.yaml 文件

步骤

  1. 在你的 Go 文件中使用 //go:embed 来嵌入文件。
  2. 使用 var 变量来接收嵌入的内容。

示例代码

假设你有一个 config.yaml 文件,内容如下:

yaml
app_name: MyApp
version: 1.0

你可以这样在 Go 程序中嵌入该文件:

go
// main.go
package main

import (
	_ "embed"
	"fmt"
	"log"

	"gopkg.in/yaml.v2"
)

//go:embed config.yaml
var configData []byte

type Config struct {
	AppName string `yaml:"app_name"`
	Version string `yaml:"version"`
}

func main() {
	// 解码嵌入的 YAML 内容
	var config Config
	err := yaml.Unmarshal(configData, &config)
	if err != nil {
		log.Fatal(err)
	}

	// 输出解析后的内容
	fmt.Printf("App Name: %s, Version: %s\n", config.AppName, config.Version)
}

说明:

  • //go:embed config.yaml 告诉 Go 将 config.yaml 文件的内容嵌入到 configData 变量中。
  • var configData []byte 用于存储嵌入的文件内容,这里是以字节切片的形式存储 YAML 文件内容。
  • 使用 yaml.Unmarshal 将字节数据反序列化为结构体。

2. 嵌入多个文件

你也可以嵌入多个文件或整个文件夹。

示例:嵌入多个文件

假设你有两个配置文件:config.yamlanother_config.yaml,你可以这样嵌入它们:

go
//go:embed config.yaml another_config.yaml
var configFiles embed.FS

这里使用 embed.FS 类型来存储文件系统,允许你按需读取嵌入的文件。

示例代码:

go
// main.go
package main

import (
	"embed"
	"fmt"
	"io/fs"
	"log"

	"gopkg.in/yaml.v2"
)

//go:embed config.yaml another_config.yaml
var configFiles embed.FS

type Config struct {
	AppName string `yaml:"app_name"`
	Version string `yaml:"version"`
}

func main() {
	// 读取嵌入的文件
	data, err := fs.ReadFile(configFiles, "config.yaml")
	if err != nil {
		log.Fatal(err)
	}

	var config Config
	err = yaml.Unmarshal(data, &config)
	if err != nil {
		log.Fatal(err)
	}

	// 输出解析后的内容
	fmt.Printf("App Name: %s, Version: %s\n", config.AppName, config.Version)

	// 读取另一个配置文件
	anotherData, err := fs.ReadFile(configFiles, "another_config.yaml")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Another Config File Contents:")
	fmt.Println(string(anotherData))
}

说明:

  • //go:embed config.yaml another_config.yaml 告诉 Go 将 config.yamlanother_config.yaml 两个文件的内容嵌入到 configFiles 变量中,configFiles 是一个 embed.FS 类型的文件系统对象。
  • 使用 fs.ReadFile(configFiles, "config.yaml") 来读取嵌入的文件内容。

3. 嵌入整个文件夹

你也可以将整个文件夹嵌入到 Go 程序中,这在需要嵌入大量资源文件时非常有用。

示例:嵌入一个文件夹

假设你有一个 assets 文件夹,包含多个文件,想要将整个文件夹嵌入到程序中:

go
//go:embed assets/*
var assets embed.FS

示例代码:

go
// main.go
package main

import (
	"embed"
	"fmt"
	"io/fs"
	"log"
)

//go:embed assets/*
var assets embed.FS

func main() {
	// 读取嵌入的文件夹中的某个文件
	data, err := fs.ReadFile(assets, "assets/config.yaml")
	if err != nil {
		log.Fatal(err)
	}

	// 打印文件内容
	fmt.Println(string(data))
}

说明:

  • //go:embed assets/* 将整个 assets 文件夹中的所有文件嵌入到 assets 变量中,assets 是一个 embed.FS 类型的文件系统对象。
  • 使用 fs.ReadFile(assets, "assets/config.yaml") 来读取嵌入的 assets/config.yaml 文件。

4. 嵌入二进制文件

embed 还可以用于嵌入二进制文件,如图片、音频文件等。你可以像处理文本文件一样处理二进制数据。

示例:嵌入图片文件

假设你要嵌入一个图片文件 logo.png

go
//go:embed logo.png
var logo []byte

然后,你可以在应用中使用这个 logo 字节数据来做一些处理,比如将其输出到一个 Web 页面上,或者保存到磁盘。

5. 限制与注意事项

  • embed 只支持嵌入 Go 源文件所在目录下的文件,不能跨目录。
  • 嵌入的文件内容在编译时确定,因此需要重新编译程序才能更新文件内容。
  • embed.FS 提供了一些文件操作方法,如 ReadFile,可以像操作普通文件系统一样访问嵌入的文件。

总结

  • embed 是 Go 1.16 引入的强大功能,允许将文件嵌入到二进制中。
  • 使用 //go:embed 注释来指定要嵌入的文件或文件夹。
  • 使用 embed.FS 来操作嵌入的文件,支持按文件读取。
  • 适用于配置文件、模板、静态资源等的打包和分发。