最近闲的没事干在捣鼓 fyne
,想用Golang去写桌面程序(图一乐),因为要解决 fyne
的中文乱码问题,需要将字体文件打包时内嵌到程序中,捣鼓了半天没搞定,突然发现了Golang的新特性,就用了一下,还挺有意思的,所以就顺便记录一下。当然,他不仅限于这种需求,比如在部署后端Web的时候,需要的一些静态资源,比如一些模板、css、js、图片等文件,也可以通过这样的方式打包到一个二进制文件中。
embed介绍
首先,embed
是 go 1.16
才有的新特性,使用方法非常简单,通过 //go:embed
指令,在打包时将文件内嵌到程序中。
快速开始
文件结构
.
├── go.mod
├── main.go
└── resources
└── hello.txt
代码:
package main
import (
_ "embed"
"fmt"
)
//embed指令↓
//go:embed resources/hello.txt
var s string
func main() {
fmt.Println(s)
}
//输出:
//hello embed!
嵌入为字符串
快速开始就是嵌入为字符串的例子,不再多赘述
嵌入为byte slice
可以直接以二进制形式嵌入,即嵌入为 byte slice
同样时快速开始里面的文件结构
我们将代码改成如下:
package main
import (
_ "embed"
"fmt"
)
//go:embed resources/hello.txt
var b []byte
func main() {
fmt.Println(string(b[0]))
fmt.Println(string(b))
}
//输出:
//h
//hello embed!
嵌入为embed.FS
你甚至能嵌入一个文件系统,此时,你能够读取到目录树和文件树,embed.FS
对外存在以下方法:
// Open 打开要读取的文件,并返回文件的fs.File结构.
func (f FS) Open(name string) (fs.File, error)
// ReadDir 读取并返回整个命名目录
func (f FS) ReadDir(name string) ([]fs.DirEntry, error)
// ReadFile 读取并返回name文件的内容.
func (f FS) ReadFile(name string) ([]byte, error)
映射单个/多个文件
文件结构:
.
├── go.mod
├── main.go
└── resources
├── hello1.txt
└── hello2.txt
代码:
package main
import (
"embed"
_ "embed"
"fmt"
)
//go:embed resources/hello1.txt
//go:embed resources/hello2.txt
var f embed.FS
func main() {
hello1, _ := f.ReadFile("resources/hello1.txt")
fmt.Println(string(hello1))
hello2, _ := f.ReadFile("resources/hello2.txt")
fmt.Println(string(hello2))
}
//输出:
//hello1
//hello2
映射目录
文件结构
.
├── go.mod
├── main.go
└── resources
├── dir1
│ └── dir1.txt
├── dir2
│ ├── dir2.txt
│ └── dir3
│ └── dir3.txt
├── hello1.txt
└── hello2.txt
代码:
package main
import (
"embed"
_ "embed"
"fmt"
)
//go:embed resources/*
var f embed.FS
func main() {
hello1, _ := f.ReadFile("resources/hello1.txt")
fmt.Println(string(hello1))
hello2, _ := f.ReadFile("resources/hello2.txt")
fmt.Println(string(hello2))
dir1, _ := f.ReadFile("resources/dir1/dir1.txt")
fmt.Println(string(dir1))
dir2, _ := f.ReadFile("resources/dir2/dir2.txt")
fmt.Println(string(dir2))
dir3, _ := f.ReadFile("resources/dir2/dir3/dir3.txt")
fmt.Println(string(dir3))
}
//输出:
//hello1
//hello2
//dir1
//dir2
//dir3