golang1.16内嵌静态资源指南

今天是万圣节,也是golang1.16新特性冻结的日子。不得不说自从go2路线发布之后golang新特性的迭代速度也飞速提升,1.16中有相当多的重要更新,包括io标准库的重构,语言内置的静态资源嵌入等。

本次将要介绍的是新的静态资源嵌入功能,虽然之前已经有相关的提案,但实际的api和提案还有些出入,今天新特性冻结也就意味着1.16的api已经趋于稳定,是时候学习新知识了。

为什么我们需要嵌入静态资源

先问是不是,再问为什么。

我们确实需要把静态资源嵌入在程序里,原因无外乎以下几点:

部署程序更简单。传统部署要么需要把静态资源和编译好的程序一起打包上传,要么使用docker和dockerfile自动化前者,心智负担较重;

保证程序完整性。运行中发生静态资源损坏或丢失往往会影响程序的正常运行;

可以自主控制程序需要的静态资源。

最常见的,比如一个静态网站的后端程序,本来需要把程序和它依赖的html模板,css,js,图片一起上传至生产服务器,同时还要正确配置静态资源在web服务器中的路径才能让用户正常访问。现在我们把这些资源全部嵌入在程序中,部署时只需要部署一个二进制文件,配置也只需要针对这个程序本身进行,部署流程被大大简化了。

另一个更常见的例子是Qt。Qt提供了qrc进行静态资源的嵌入,将图片,声音等资源嵌入在程序中,Qt程序可以更方便地在各个平台上进行分发安装,同时还能提供较为一致的用户体验。

golang1.16前如何嵌入静态资源

在1.16之前我们需要借助工具来实现。这些工具都是借助代码生成来完成资源嵌入的,我们拿使用的最多的_packr_举例,项目链接在这里:https://github.com/gobuffalo/packr。

首先我们创建一个项目:

mkdir pk && cd pk go mod init my.mod/pk go get -u github.com/gobuffalo/packr/v2/... # 安装库 go get -u github.com/gobuffalo/packr/v2/packr2 # 安装资源打包工具

然后我们复制一个png图片和一个录屏软件制造的巨型gif文件进images文件夹,整个项目看起来如下:

golang1.16内嵌静态资源指南

然后是我们的代码:

package main import ( "fmt" "github.com/gobuffalo/packr/v2" ) func main() { box := packr.New("myBox", "./images") // 创建内嵌资源 data, err := box.Find("screenrecord.gif") // 查找内嵌资源 if err != nil { log.Fatal(err) } fmt.Println(len(data)) }

想要完成资源嵌入,我们需要运行packr2命令,之后直接运行go build即可,顺利运行后项目会是这样:

golang1.16内嵌静态资源指南

packr的思路就是将资源文件编码成合法的golang源文件,然后利用golang把这些代码化的资源编译进程序里。这是比较主流的嵌入资源实现方案。

从上面的例子里我们可以看到这类方法有不少缺点:

需要安装额外的工具

会生成超大体积的生产代码(是静态资源的两倍大,因为需要对二进制数据进行一定的编码才能正常存储在go源文件里)

编译完成的程序体积也是资源文件的两倍多

程序加载时间长,上图中程序运行花费了6秒,我们程序是存放在ssd上的,慢是因为库需要对编码的资源进行处理

前两点通过语言内置工具或机制就可以得到解决,而对于后两点,静态资源本身在计算机上也是二进制存储的,重复编码解码浪费时间,如果可以直接把资源放进程序里该多好。同时告别了生成代码还可以让我们的项目结构更清晰。

所以,golang1.16的官方内置版静态资源嵌入方案诞生了。

准备工作

golang的embed需要在1.16及之后的版本才能运行,不过我们已经可以自行编译尝鲜了(需要电脑已经安装了稳定版本的golang):

mkdir -p ~/go-next && cd ~/go-next git clone https://github.com/golang/go cd go/src && bash ./make.bash export GOROOT=~/go-next/go alias newgo=${GOROOT}/bin/go

验证一下安装:

$ newgo version go version devel +256d729c0b Fri Oct 30 15:26:28 2020 +0000 linux/amd64

至此准备工作就结束了。

如何匹配静态资源

想要嵌入静态资源,首先我们得利用embed这个新的标准库。在声明静态资源的文件里我们需要引入这个库。

对于我们想要嵌入进程序的资源,需要使用//go:embed指令进行声明,注意//之后不能有空格。具体格式如下:

//go:embed pattern // pattern是path.Match所支持的路径通配符

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsffsd.html