Go Embed

embed.String

import _ "embed"

//go:embed message.txt
var message string

func main() {
    fmt.Println(message)
}

embed.Bytes

import _ "embed"

//go:embed schema.sql
var schema []byte

//go:embed favicon.ico
var favicon []byte

func main() {
    fmt.Println(string(schema))
}

embed.FS

import "embed"

//go:embed static/*
var staticFS embed.FS

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

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

Embed Files

import _ "embed"

//go:embed hello.txt
var hello string

//go:embed hello.txt
var helloBytes []byte

//go:embed a.txt b.txt
var multiFile embed.FS

Embed Directories

//go:embed assets
var assets embed.FS

//go:embed static/img static/css
var webAssets embed.FS

data, _ := assets.ReadFile("assets/logo.png")
entries, _ := assets.ReadDir("assets")
for _, e := range entries {
    fmt.Println(e.Name(), e.IsDir())
}

HTTP File Server

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

func main() {
    fs, _ := fs.Sub(static, "static")
    http.Handle("/", http.FileServer(http.FS(fs)))
    http.ListenAndServe(":8080", nil)
}

ReadFile / ReadDir

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

content, err := data.ReadFile("data/config.json")
entries, err := data.ReadDir("data")

file, err := data.Open("data/config.json")
stat, err := file.Stat()

Sub FS

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

subFS, err := fs.Sub(static, "static")
if err != nil {
    log.Fatal(err)
}

http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(subFS))))

Match Patterns

//go:embed *.txt
var txtFiles embed.FS

//go:embed a.txt b.txt c.txt
var specific embed.FS

//go:embed **/*.json
var jsonFiles embed.FS

//go:embed images/*.png images/*.jpg
var images embed.FS

//go:embed LICENSE README.md
var docs embed.FS

Embed Templates

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

func main() {
    tmpl, err := template.ParseFS(templateFS, "templates/*.html")
    if err != nil {
        log.Fatal(err)
    }
    tmpl.Execute(os.Stdout, map[string]string{"Title": "Hello"})
}

Embed Config

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

func main() {
    var cfg struct {
        Port int    `json:"port"`
        Host string `json:"host"`
    }
    if err := json.Unmarshal(configData, &cfg); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("serving on %s:%d\n", cfg.Host, cfg.Port)
}

Embed Frontend SPA

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

func main() {
    subFS, _ := fs.Sub(dist, "dist")
    http.Handle("/", http.FileServer(http.FS(subFS)))
    http.HandleFunc("/api", apiHandler)
    http.ListenAndServe(":8080", nil)
}

Build Constraints

// +build !dev

//go:embed static/*
var staticFS embed.FS
// +build dev

// use filesystem directly in dev mode
var staticFS = os.DirFS("static")

Limitations

// only works in package-level vars, not inside functions
// BAD:
func main() {
    //go:embed hello.txt
    var s string
}

// GOOD:
//go:embed hello.txt
var s string

// embed patterns use glob syntax, not regex
// hidden files (starting with .) are excluded by default
// use explicit pattern to include:
//go:embed .hidden
var hidden string

// does not follow symlinks
// paths must be relative (no leading /)
// cannot embed files outside the module

embed.String

import _ "embed"

//go:embed message.txt
var message string

func main() {
    fmt.Println(message)
}

embed.Bytes

import _ "embed"

//go:embed schema.sql
var schema []byte

//go:embed favicon.ico
var favicon []byte

func main() {
    fmt.Println(string(schema))
}

embed.FS

import "embed"

//go:embed static/*
var staticFS embed.FS

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

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

Embed Files

import _ "embed"

//go:embed hello.txt
var hello string

//go:embed hello.txt
var helloBytes []byte

//go:embed a.txt b.txt
var multiFile embed.FS

Embed Directories

//go:embed assets
var assets embed.FS

//go:embed static/img static/css
var webAssets embed.FS

data, _ := assets.ReadFile("assets/logo.png")
entries, _ := assets.ReadDir("assets")
for _, e := range entries {
    fmt.Println(e.Name(), e.IsDir())
}

HTTP File Server

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

func main() {
    fs, _ := fs.Sub(static, "static")
    http.Handle("/", http.FileServer(http.FS(fs)))
    http.ListenAndServe(":8080", nil)
}

ReadFile / ReadDir

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

content, err := data.ReadFile("data/config.json")
entries, err := data.ReadDir("data")

file, err := data.Open("data/config.json")
stat, err := file.Stat()

Sub FS

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

subFS, err := fs.Sub(static, "static")
if err != nil {
    log.Fatal(err)
}

http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(subFS))))

Match Patterns

//go:embed *.txt
var txtFiles embed.FS

//go:embed a.txt b.txt c.txt
var specific embed.FS

//go:embed **/*.json
var jsonFiles embed.FS

//go:embed images/*.png images/*.jpg
var images embed.FS

//go:embed LICENSE README.md
var docs embed.FS

Embed Templates

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

func main() {
    tmpl, err := template.ParseFS(templateFS, "templates/*.html")
    if err != nil {
        log.Fatal(err)
    }
    tmpl.Execute(os.Stdout, map[string]string{"Title": "Hello"})
}

Embed Config

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

func main() {
    var cfg struct {
        Port int    `json:"port"`
        Host string `json:"host"`
    }
    if err := json.Unmarshal(configData, &cfg); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("serving on %s:%d\n", cfg.Host, cfg.Port)
}

Embed Frontend SPA

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

func main() {
    subFS, _ := fs.Sub(dist, "dist")
    http.Handle("/", http.FileServer(http.FS(subFS)))
    http.HandleFunc("/api", apiHandler)
    http.ListenAndServe(":8080", nil)
}

Build Constraints

// +build !dev

//go:embed static/*
var staticFS embed.FS
// +build dev

// 开发模式直接使用文件系统
var staticFS = os.DirFS("static")

Limitations

// 只能用于包级别变量,不能在函数内使用
// BAD:
func main() {
    //go:embed hello.txt
    var s string
}

// GOOD:
//go:embed hello.txt
var s string

// 模式使用 glob 语法,不是正则
// 隐藏文件(以 . 开头)默认被排除
// 需要显式指定才能包含:
//go:embed .hidden
var hidden string

// 不跟踪符号链接
// 路径必须为相对路径(无前导 /)
// 不能嵌入模块外部的文件