最近需要使用 golang1.16 中的功能 embed ,本文简单记录下 embed 的使用。
embed 介绍
Go 1.16 引入了embed包,允许我们在编译时将静态文件(例如 .go、.html、.css、.js 等)嵌入到 Go 源文件中。这在构建静态网站、单页应用程序(SPA)和其他项目时非常有用。
主要有几个优点:
方便部署:不需要再部署静态资源文件,所有的资源都直接嵌入到可执行文件中。
安全:用户无法直接访问或修改嵌入的文件。
版本管理:和Go代码一起版本控制。
使用
嵌入为字符串
可以将文件内容保存到字符串变量中。
package main
import (
_ "embed"
"fmt"
)
//go:embed hello.txt
var s string
func main() {
fmt.Println(s)
}
文件路径下有个 hello.txt,内容如下:hello, overstarry
,代码运行输出:hello, overstarry
保存为 []bytes
还可以将文件内容保存为 []bytes变量
package main
import (
_ "embed"
"fmt"
)
//go:embed hello.txt
var s []byte
func main() {
fmt.Println(string(s))
}
运行代码输出内容与上面一致。
保存为 fs.FS 类型
还可以将文件保存为 fs.FS 类型,这在嵌入多个文件时非常有用(string和[]bytes不支持多个//go:embed指令)。
package main
import (
"embed"
"fmt"
)
//go:embed hello.txt
//go:embed hello2.txt
var f embed.FS
func main() {
data, _ := f.ReadFile("hello.txt")
fmt.Println(string(data))
data, _ = f.ReadFile("hello2.txt")
fmt.Println(string(data))
}
嵌入的内容是只读的。也就是在编译期嵌入文件的内容是什么,那么在运行时的内容也就是什么。
FS文件系统值提供了打开和读取的方法,并没有write的方法,也就是说FS实例是线程安全的,多个goroutine可以并发使用。
单个文件嵌入为多个变量
还可以将单个文件保存为多个变量。
package main
import (
_ "embed"
"fmt"
)
//go:embed hello.txt
var s string
//go:embed hello.txt
var s2 string
func main() {
fmt.Println(s)
fmt.Println(s2)
}
将 hello.txt的内容保存为 s和s2变量以供不同地方使用。
文件嵌入为可导出变量
可以将文件嵌入为可导出变量和不可导出变量,以应对需要外部调用的场景。
package main
import (
_ "embed"
"fmt"
)
//go:embed hello.txt
var S string
//go:embed hello.txt
var s2 string
func main() {
fmt.Println(S)
fmt.Println(s2)
}
嵌入多个文件
go:embed指令支持嵌入多个文件
package main
import (
"embed"
"fmt"
)
//go:embed hello.txt hello2.txt
var f embed.FS
func main() {
data, _ := f.ReadFile("hello.txt")
fmt.Println(string(data))
data, _ = f.ReadFile("hello2.txt")
fmt.Println(string(data))
}
嵌入文件夹
除了支持文件嵌入还可以嵌入整个文件夹。需要注意的是文件夹分隔符使用/
,windows环境也是。
package main
import (
"embed"
"fmt"
)
//go:embed p
var f embed.FS
func main() {
data, _ := f.ReadFile("p/hello.txt")
fmt.Println(string(data))
data, _ = f.ReadFile("p/hello2.txt")
fmt.Println(string(data))
}
小结
除了上面介绍的一些功能,embed还支持相对路径等功能,感兴趣的读者可以自行查阅相关资料。