Go 开发中的go:embed应用与最佳实践
go:embed
使用介绍
go:embed
是 Go 语言的一项编译器指令,它允许在编译时将任意文件或目录嵌入到 Go 的二进制文件中。通过这种方式,开发者可以在不依赖外部文件的情况下直接在代码中访问这些资源,从而提高了程序的独立性和资源管理的灵活性。
特点
- 文件嵌入类型: 对于单个文件,
go:embed
可以将其嵌入为字符串 (string
) 或字节切片 ([]byte
)。对于多个文件或目录,则可以嵌入为文件系统 (embed.FS
)。 - 灵活性: 即使嵌入的文件变量未被显式使用,只要导入了
embed
包,文件仍然会被嵌入。 - 语法要求:
go:embed
指令必须紧跟在要嵌入文件的变量声明之前,并且该变量必须是string
、[]byte
或embed.FS
类型,其他类型(如自定义类型)不支持。
使用方法
go:embed
的用法非常简单,以下是几种常见的应用场景:
import "embed"
//go:embed mobile.txt
var mobile string
//go:embed hello.txt
var contentBytes []byte
//go:embed hello.txt
var fileFS embed.FS
在上述示例中,mobile.txt
文件被嵌入到 mobile
字符串中,hello.txt
文件被嵌入为字节切片,而 fileFS
则作为文件系统,通过 fileFS.ReadFile("hello.txt")
来读取文件内容。
嵌入为字符串
适合嵌入小型的文本文件,如配置文件、模板等。
package main
import (
_ "embed"
"fmt"
)
//go:embed hello.txt
var pfinal string
func main() {
fmt.Println(pfinal)
}
嵌入为字节切片
适合嵌入非文本文件,如图片、字体等二进制数据。
package main
import (
_ "embed"
"fmt"
)
//go:embed hello.txt
var pfinal []byte
func main() {
fmt.Println(pfinal)
}
嵌入为 embed.FS
适合嵌入多个文件或整个目录,嵌入后可以使用 embed.FS
提供的接口来读取文件。
package main
import (
_ "embed"
"embed"
"fmt"
)
//go:embed hello.txt
var pfinal embed.FS
func main() {
data, _ := pfinal.ReadFile("hello.txt")
fmt.Println(string(data))
}
多文件嵌入
go:embed
支持在 embed.FS
上嵌入多个文件,多个文件可以通过多行 go:embed
指令来实现(注意 string
和 []byte
不能有多个 go:embed
指令)。
//go:embed pfinal.txt
//go:embed hello.txt
var pfinal embed.FS
func main() {
data, _ := pfinal.ReadFile("pfinal.txt")
fmt.Println(string(data))
data, _ = pfinal.ReadFile("hello.txt")
fmt.Println(string(data))
}
嵌入目录
通过 go:embed
,我们还可以嵌入整个目录,除了以 .
和 _
开头的文件默认不被嵌入之外,其他文件都会嵌入。
//go:embed pfinal/*
var pfinal embed.FS
func main() {
data, _ := pfinal.ReadFile("pfinal/.pfinal.txt")
fmt.Println(string(data))
}
如果需要嵌入以 .
和 _
开头的文件,必须明确使用通配符,例如 go:embed p/*
。注意通配符不具备递归嵌入的功能,如果要嵌入子文件夹,需要在子文件夹中也使用通配符。
只读限制
嵌入的文件内容是只读的,不能在运行时修改这些嵌入的文件。embed.FS
作为只读的虚拟文件系统,支持基本的文件读取操作,但不支持写入。因此,多个 Goroutine 可以并发访问而不会出现竞争条件。
type FS
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)
文件模式匹配
在 go:embed
指令中可以指定文件夹路径,如果仅指定文件夹路径,除 .
和 _
开头的文件以外,所有文件都会被嵌入,且嵌入操作是递归的。如果希望嵌入特定文件,或者嵌入以 .
和 _
开头的文件,必须使用通配符 *
。
嵌入多个文件:
//go:embed "hello.txt" "hello-2.txt" var f embed.FS
嵌入当前目录的所有文件(除了
.
和_
开头的文件)://go:embed * var f embed.FS
示例:嵌入数据并读取
以下是一个嵌入二进制文件(如数据库文件)的示例:
package main
import (
"embed"
"fmt"
)
//go:embed phone.dat
var fsContent embed.FS
func main() {
data, err := fsContent.ReadFile("phone.dat")
if err != nil {
panic(err)
}
fmt.Println(data)
}
该示例中,phone.dat
文件被嵌入到 fsContent
中,可以在程序运行时直接读取该文件内容。
版权声明:本文为原创文章,版权归 全栈开发技术博客 所有。
本文链接:https://www.lvtao.net/dev/go-embed.html
转载时须注明出处及本声明