go1.16 - go:embed 指令用法

2021-02-28 · xiejiahe

go1.16 出了 go:embed 指令, 了解后发现很强!!!

作用

go:embed 是一个指令,用来嵌入静态文件到二进制文件当中。

我们在部署时会打包成一个二进制文件,如果应用包含一些配置文件比如 config.ini / index.html config.yaml 等一系列静态文件就比较麻烦了,在以往的做法就是将这些静态文件放到二进制同一个目录里头,通过文件系统进行读取, 或者是写在 .go 文件里, 就很不方便。

现在可以通过 go:embed 指令将这些静态文件打包在二进制文件里,也就是只有一个二进制文件。

规则

在使用 go:embed 指令之前先了解一下有哪些限制。

  • 如果 go:embed 指令跟着单个文件,只支持 string / []byte / embed.FS
  • 如果 go:embed 指令跟着多个文件或文件夹,只支持 embed.FS
  • go:embed 指令下一行必须紧跟着嵌入变量
  • 只支持全局变量
  • 只支持 string / []byte / embed.FS, 其他类型包括别名都不支持
  • 嵌入文件路径不支持绝对路径,不支持路径中包含 . / .., 当前路径使用 *

来个典型的例子

2.txt 文件内容:

hello golang
package main

import (
    _ "embed"
    "fmt"
)

//go:embed 2.txt
var s string
func main() {
    fmt.Println(s)
    // hello golang
}

注意 // 注释后面不能有空格

[]byte

字节切片类型:

package main

import (
    _ "embed"
    "fmt"
)

//go:embed 2.txt
var b []byte
func main() {
    fmt.Println(b)
    // [104 101 108 108 111 32 103 111 108 97 110 103]
}

嵌入文件系统

package main

import (
    "embed"
    "fmt"
)

//go:embed 2.txt
var f embed.FS

func main() {
    s, _ := f.ReadFile("2.txt")
    fmt.Println(string(s))
    // hello golang
}

嵌入多个文件

当嵌入多个文件只能使用 embed.FS 类型,不支持其他类型。

package main

import (
    "embed"
    "fmt"
)

//go:embed 1.txt 2.txt
var f embed.FS
func main() {
    s1, _ := f.ReadFile("1.txt")
    s2, _ := f.ReadFile("2.txt")
    fmt.Println(string(s1))
    fmt.Println(string(s2))
}

或者指令分开多行写也可以

package main

import (
    "embed"
    "fmt"
)

//go:embed 1.txt
//go:embed 2.txt
var f embed.FS
func main() {
    s1, _ := f.ReadFile("1.txt")
    s2, _ := f.ReadFile("2.txt")
    fmt.Println(string(s1))
    fmt.Println(string(s2))
}

FS 是只读的

FS 目前提供了3个API:

  • func (f FS) Open(name string) (fs.File, error)
  • func (f FS) ReadDir(name string) ([]fs.DirEntry, error)
  • func (f FS) ReadFile(name string) ([]byte, error)

这3个都是只读的,没有可写的接口, 也就是不存在竞态问题,可以并发读取。

embed.FS 实现了 1.16 io/fs.FS 新的接口:

package main

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

//go:embed 1.txt
var f embed.FS
func main() {
    content, _ := fs.ReadFile(f, "1.txt")
    fmt.Println(string(content))
}

嵌入文件夹

采用 / 斜杠来访问目录下的文件,windows 也一样。

当嵌入的是文件夹时除了 ._ 开头的文件和文件夹都会被嵌入即使在程序中没有使用。

package main

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

//go:embed test
var f embed.FS
func main() {
    content, _ := fs.ReadFile(f, "test/1.txt")
    fmt.Println(string(content))
    // hello golang
}
Golang
原创文章,转载请注明出处。