Go embed 静态文件嵌入

FreeGuideOnline 最新 2026-07-11

{{.Message}}

```

代码示例:

package main

import (
    "embed"
    "html/template"
    "log"
    "net/http"
)

//go:embed data/templates/*
var templateFS embed.FS

func main() {
    // 使用 ParseFS 一次性解析嵌入文件系统中的所有模板
    tmpl, err := template.New("").ParseFS(templateFS, "data/templates/*.html")
    if err != nil {
        log.Fatal(err)
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        data := struct {
            Title   string
            Message string
        }{
            Title:   "Embed Demo",
            Message: "模板嵌入成功!",
        }
        tmpl.ExecuteTemplate(w, "index.html", data)
    })

    log.Println("Server started on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
  • template.New("").ParseFS(templateFS, "data/templates/*.html") 直接从 embed.FS 解析所有匹配的 HTML 模板。
  • 模板名称会自动去除路径前缀,保留文件名。因此执行时使用 index.html 即可。

常用模式与最佳实践

条件编译与路径变量

一个常见的需求是为不同环境嵌入不同的配置文件。可以通过构建标签结合变量实现:

目录结构:

config/
  config_dev.go
  config_prod.go
main.go

config_dev.go

//go:build dev

package main

import _ "embed"

//go:embed config_dev.json
var configJSON []byte

config_prod.go

//go:build prod

package main

import _ "embed"

//go:embed config_prod.json
var configJSON []byte

main.go 中直接使用全局变量 configJSON。编译时指定标签即可切换:

  • 开发环境:go build -tags dev
  • 生产环境:go build -tags prod

嵌入的注意事项

  1. 路径安全go:embed 不允许使用 .. 或绝对路径,只能引用当前模块内的子路径。
  2. 空目录不会被嵌入:即使目录存在,如果目录中没有 go:embed 匹配的文件,该目录不会被包含。
  3. 文件嵌入变量必须为包级别变量,局部变量不支持。
  4. 不可嵌入符号链接,若路径指向软链接,编译将报错。
  5. 文件变化不影响已编译的二进制。嵌入发生在编译期,运行时无法动态更新。若需要热更新,应考虑外部文件或引入额外的文件监听机制。

查看嵌入列表与调试

可以使用标准库 fs.WalkDir 遍历 embed.FS,打印所有可用的嵌入文件路径。这对于在开发阶段验证嵌入内容十分有用:

func printEmbedFiles(efs embed.FS) {
    fs.WalkDir(efs, ".", func(path string, d fs.DirEntry, err error) error {
        if err != nil {
            return err
        }
        fmt.Println(path)
        return nil
    })
}