具体的通配符如下,如果你是在linux系统上,可以用man 7 glob查看更详细的教程:
通配符 释义? 代表任意一个字符(不包括半角中括号)
* 代表0至多个任意字符组成的字符串(不包括半角中括号)
[...]和[!...] 代表任意一个匹配方括号里字符的字符,!表示任意不匹配方括号中字符的字符
[a-z]、[0-9] 代表匹配a-z任意一个字符的字符或是0-9中的任意一个数字
** 部分系统支持,*不能跨目录匹配,**可以,不过目前个golang中和*是同义词
我们可以在embed的pattern里自由组合这些通配符。
golang的embed默认的根目录从module的目录开始,路径开头不可以带/,不管windows还是其他系统路径分割副一律使用/。如果匹配到的是目录,那么目录下的所有文件都会被嵌入(有部分文件夹和文件会被排除,后面详细介绍),如果其中包含有子目录,则对子目录进行递归嵌入。
下面举一些例子,假设我们的项目在/tmp/proj:
//go:embed images 这是匹配所有位于/tmp/proj/images及其子目录中的文件 //go:embed images/jpg/a.jpg 匹配/tmp/proj/images/jpg/a.jpg这一个文件 //go:embed a.txt 匹配/tmp/proj/a.txt //go:embed images/jpg/*.jpg 匹配/tmp/proj/images/jpg下所有.jpg文件 //go:embed images/jpg/a?.jpg 匹配/tmp/proj/images/jpg下的a1.jpg a2.jpg ab.jpg等 //go:embed images/??g/*.* 匹配/tmp/proj/images下的jpg和png文件夹里的所有有后缀名的文件,例如png/123.png jpg/a.jpeg //go:embed * 直接匹配整个/tmp/proj //go:embed a.txt //go:embed *.png *.jpg //go:embed aa.jpg 可以指定多个//go:embed指令行,之间不能有空行,也可以用空格在一行里写上对个模式匹配,表示匹配所有这些文件,相当于并集操作 可以包含重复的文件或是模式串,golang对于相同的文件只会嵌入一次,很智能 如何使用嵌入的静态资源在了解了如何指定需要的静态资源之后,我们该学习如何使用它们了,还记得我们前面提到的embed标准库吗?
对于一个完整的嵌入资源,代码中的声明是这样的:
//go:embed images var imgs embed.FS //go:embed a.txt var txt []byte //go:embed b.txt var txt2 string一共有三种数据格式可选:
数据类型 说明[]byte 表示数据存储为二进制格式,如果只使用[]byte和string需要以import (_ "embed")的形式引入embed标准库
string 表示数据被编码成utf8编码的字符串,因此不要用这个格式嵌入二进制文件比如图片,引入embed的规则同[]byte
embed.FS 表示存储多个文件和目录的结构,[]byte和string只能存储单个文件
下面看个具体例子,目录结构如下:
$ tree -sh . . ├── [ 487] embed_fs.go ├── [ 235] embed_img.go ├── [ 187] embed_img2.go ├── [ 513] embed_img_fs.go ├── [ 211] embed_text.go ├── [ 660] embed_text_fs.go ├── [ 30] go.mod ├── [ 0] imgs │ ├── [ 0] jpg │ │ ├── [606K] a.jpg │ │ ├── [976K] b.jpg │ │ └── [342K] c.jpg │ ├── [ 0] png │ │ ├── [4.7M] a.png │ │ ├── [1.4M] b.png │ │ └── [1.7M] c.png │ └── [ 77M] screenrecord.gif ├── [ 98K] macbeth.txt └── [ 0] texts ├── [ 12] en.txt ├── [ 25] jp.txt └── [ 16] zh.txt 4 directories, 18 files目录包含了一些静态图片,一个录屏文件,一个莎士比亚的麦克白剧本。当然还有我们的测试代码。
处理单个文件我们先来看用[]byte和string嵌入单个文件的例子:
package main import ( "fmt" _ "embed" ) //go:embed macbeth.txt var macbeth string func main(){ fmt.Println(len(macbeth)) // 麦克白的总字符数 //go:embed texts/en.txt var hello string fmt.Println(hello) // Output: Hello, world }如你所见,嵌入内容声明可以放进任意作用域,但变量一定要求用var声明。直接使用newgo run embed_txt.go或go build embed_txt.go && ./embed_txt即可完成编译运行,过程中不会生成任何中间代码。另外变量是否是公开的(首字母是否大小写)并不会对资源的嵌入产生影响。
再来看看二进制文件的例子,embed_img.go如下所示:
package main import ( "fmt" _ "embed" ) //go:embed imgs/screenrecord.gif var gif []byte //go:embed imgs/png/a.png var png []byte func main() { fmt.Println("gif size:", len(gif)) // gif size: 81100466 fmt.Println("png size:", len(png)) // png size: 4958264 }如果编译运行这个程序,你会发现二进制文件的大小是89M(不同系统会有差异),比我们之前使用packr创建的要小了许多。
处理多个文件和目录下面就要进入本文的重头戏了,新的标准库embed的使用。