[golang]Go内嵌静态资源go-bindata的安装及使用
使用 Go 开发应用的时候,有时会遇到需要读取静态资源的情况。比如开发 Web 应用,程序需要加载模板文件生成输出的 HTML。在程序部署的时候,除了发布应用可执行文件外,还需要发布依赖的静态资源文件。这给发布过程添加了一些麻烦。既然发布单独一个可执行文件是非常简单的操作,就有人会想办法把静态资源文件打包进 Go 的程序文件中。下面就来看一些解决方案:
go-bindata
go-bindata 是目前我的程序 pugo
在用的嵌入静态资源的工具。它可以把静态文件嵌入到一个 go 文件中,并提供一些操作方法。
安装
go-bindata
:go get -u github.com/jteeuwen/go-bindata/...
注意 go get 地址最后的三个点 ...
。这样会分析所有子目录并下载依赖编译子目录内容。go-bindata
的命令工具在子目录中。(还要记得把 $GOPATH/bin
加入系统 PATH
)。
使用命令工具 go-bindata
( pugo 的例子):
go-bindata -o=app/asset/asset.go -pkg=asset source/... theme/... doc/source/... doc/theme/...
-o
输出文件到 app/asset/asset.go
,包名 -pkg=asset
,然后是需要打包的目录,三个点包括所有子目录。这样就可以把所有相关文件打包到 asset.go
且开头是 package asset
保持和目录一致。
pugo 里释放静态文件的代码:
dirs := []string{"source", "theme", "doc"} // 设置需要释放的目录 for _, dir := range dirs {
// 解压dir目录到当前目录
if err := asset.RestoreAssets("./", dir); err != nil {
isSuccess = false
break
}
}
if !isSuccess {
for _, dir := range dirs {
os.RemoveAll(filepath.Join("./", dir))
}
}
asset.go
内的静态内容还是根据实际的目录位置索引。所以我们可以直接通过目录或者文件地址去操作。
-debug 开发模式
go-bindata
支持开发模式,即不嵌入静态内容,只生成操作方法到输出的 go 代码中,如:
go-bindata -debug -o=app/asset/asset.go -pkg=asset source/... theme/... doc/source/... doc/theme/...
-debug
参数开启开发模式。生成的代码会直接去读取静态文件到内存,而不是编码到代码中。代码文件更小,你更快速的编写业务逻辑。
// -pkg=asset, 打包的包名是 asset
bytes, err := asset.Asset("theme/default/post.html") // 根据地址获取对应内容
if err != nil {
fmt.Println(err)
return
}
t, err := template.New("tpl").Parse(string(bytes)) // 比如用于模板处理
fmt.Println(t, err)
http.FileSystem
http.FileSystem
是定义 HTTP 静态文件服务的接口。go-bindata
的第三方包 go-bindata-assetfs 实现了这个接口,支持 HTTP 访问静态文件目录的行为。以我们上面编译好的 asset.go
为例:
import (
"net/http" "github.com/elazarl/go-bindata-assetfs"
"github.com/go-xiaohei/pugo/app/asset" // 用 pugo 的asset.go进行测试
) func main() {
fs := assetfs.AssetFS{
Asset: asset.Asset,
AssetDir: asset.AssetDir,
AssetInfo: asset.AssetInfo,
}
http.Handle("/", http.FileServer(&fs))
http.ListenAndServe(":12345", nil)
}
访问 http://localhost:12345
,就可以看到嵌入的 source
,theme
,doc
的目录列表页面,和 Nginx 查看静态文件目录一样的。
go.rice
go.rice 也支持打包静态文件到 go 文件中,但是行为和 go-bindata
很不相同。从使用角度,go.rice
其实是更便捷的静态文件操作库。打包静态文件反而是顺带的功能。
安装和 go-bindata
一样,注意 三个点:
go get github.com/GeertJohan/go.rice/...
go.rice
把一个目录认为是一个 rice.Box
操作:
import (
"fmt"
"html/template" "github.com/GeertJohan/go.rice"
) func main() {
// 这里写相对于的执行文件的地址
box, err := rice.FindBox("theme/default")
if err != nil {
println(err.Error())
return
}
// 从目录 Box 读取文件
str, err := box.String("post.html")
if err != nil {
println(err.Error())
return
}
t, err := template.New("tpl").Parse(str)
fmt.Println(t, err)
}
rice 命令
go.rice
的打包命令是 rice
。用起来非常直接:在有使用 go.rice 操作的 go 代码目录,直接执行 rice embed-go
:
rice embed-go
rice -i "github.com/fuxiaohei/xyz" embed-go // -i 处理指定包里的 go.rice 操作
他就会生成当前包名下的、嵌入了文件的代码 rice-box.go
。但是,它不递归处理 import。他会分析当前目录下的 go 代码中 go.rice
的使用,找到对应需要嵌入的文件夹。但是子目录下的和 import
的里面的 go.rice
使用不会分析,需要你手动 cd 过去或者 -i
指定要处理的包执行命令。这点来说非常的不友好。
http.FileSystem
go.rice
是直接支持 http.FileSystem
接口:
func main() {
// MustFindBox 出错直接 panic
http.Handle("/", http.FileServer(rice.MustFindBox("theme").HTTPBox()))
http.ListenAndServe(":12345", nil)
}
有点略繁琐的是 rice.FindBox(dir)
只能加载一个目录。因此需要多个目录的场景,会有代码:
func main() {
http.Handle("/img", http.FileServer(rice.MustFindBox("static/img").HTTPBox()))
http.Handle("/css", http.FileServer(rice.MustFindBox("static/css").HTTPBox()))
http.Handle("/js", http.FileServer(rice.MustFindBox("static/js").HTTPBox()))
http.ListenAndServe(":12345", nil)
}
esc
esc 的作者在研究几款嵌入静态资源的工具后,发觉都不好用,就自己写出了 esc
。它的需求很简单,就是嵌入静态资源 和 支持 http.FileSystem
。esc
工具也这两个主要功能。
安装 esc
:
go get github.com/mjibson/esc
使用方法和 go-bindata
类似:
// 注意 esc 不支持 source/... 三个点表示所有子目录
go-bindata -o=asset/asset.go -pkg=asset source theme doc/source doc/theme
直接支持 http.FileSystem
:
import (
"net/http"
"asset" // esc 生成 asset/asset.go
) func main() {
fmt.Println(asset.FSString(false, "/theme/default/post.html")) // 读取单个文件
http.ListenAndServe(":12345", http.FileServer(asset.FS(false))) // 支持 http.FileSystem,但是没有做展示目录的支持
}
esc
有个较大的问题是只能一个一个文件操作,不能文件夹操作,没有类似go-bindata
的 asset.RestoreDir()
方法。并且没有方法可以列出嵌入的文件的列表,导致也无法一个一个文件操作,除非自己写死。这是我不使用他的最大原因。
go generate
嵌入静态资源的工具推荐配合 go generate 使用。例如 pugo
的入口文件就有:
package main import (
"os"
"time" "github.com/go-xiaohei/pugo/app/command"
"github.com/go-xiaohei/pugo/app/vars"
"github.com/urfave/cli"
) //go:generate go-bindata -o=app/asset/asset.go -pkg=asset source/... theme/... doc/source/... doc/theme/... // ......
在编译的时候执行:
go generate && go build
这个是 go generate
的基本用法。更详细的了解可以看 官方博文。
总结
我在开发 pugo
的时候对这几款嵌入静态资源的程序进行了测试。go.rice
并不是我想要的模式,就没有考虑。esc
提供的操作方法太少,无法满足程序开发的需要。最后选择 go-bindata
。但是 go-bindata
和 go.rice
都是将纯字符数据或 []byte 字符数据写入 go 文件,内容非常大。esc
是写入 gzip 压缩流的 Base64 编码。经过压缩后 go 代码的大小明显更少(我嵌入的都是模板等文本文件)。可见库类都有各自的优缺点。倘若有 go-bindata
那样丰富的 API,又有 esc
那样嵌入压缩过的字符数据,那该多好。
[golang]Go内嵌静态资源go-bindata的安装及使用的更多相关文章
- golang1.16内嵌静态资源指南
今天是万圣节,也是golang1.16新特性冻结的日子.不得不说自从go2路线发布之后golang新特性的迭代速度也飞速提升,1.16中有相当多的重要更新,包括io标准库的重构,语言内置的静态资源嵌入 ...
- Go 内嵌静态资源
http://fuxiaohei.me/2016/10/1/go-binary-embed-asset.html
- .NET Core的文件系统[4]:由EmbeddedFileProvider构建的内嵌(资源)文件系统
一个物理文件可以直接作为资源内嵌到编译生成的程序集中.借助于EmbeddedFileProvider,我们可以统一的编程方式来读取内嵌于某个程序集中的资源文件,不过在这之前我们必须知道如何将一个项目文 ...
- 由EmbeddedFileProvider构建的内嵌(资源)文件系统
由EmbeddedFileProvider构建的内嵌(资源)文件系统 一个物理文件可以直接作为资源内嵌到编译生成的程序集中.借助于EmbeddedFileProvider,我们可以统一的编程方式来读取 ...
- Razor Page Library:开发独立通用RPL(内嵌wwwroot资源文件夹)
ASP.NET Core知多少系列:总体介绍及目录 Demo路径:GitHub-RPL.Demo 1. Introduction Razor Page Library 是ASP.NET Core 2. ...
- Spring-Boot 内置静态资源文件地址修改
Spring-Boot 内置MVC静态文件地址修改 Why:1.Spring-Boot修改内置SpringMVC静态资源路径,提高项目目录结构的安全性.2.配置拦截路径时可以剔除静态文件拦截How:1 ...
- NanUI文档 - 打包并使用内嵌式的HTML/CSS/JS资源
NanUI文档目录 NanUI简介 开始使用NanUI 打包并使用内嵌式的HTML/CSS/JS资源 使用网页来设计整个窗口 如何实现C#与Javascript相互掉用(待更新...) 如何处理Nan ...
- 几个golang 静态资源嵌入包
静态资源嵌入二进制文件中,可以方便我们的软件分发(只需要简单的二进制文件就可以了),目前大部分golang 的 web 应用都是使用类似的方法. 以下是收集到的一些常见方案 github.com/go ...
- [ASP.NET Core 3框架揭秘] 文件系统[4]:程序集内嵌文件系统
一个物理文件可以直接作为资源内嵌到编译生成的程序集中.借助于EmbeddedFileProvider,我们可以采用统一的编程方式来读取内嵌的资源文件,该类型定义在 "Microsoft.Ex ...
随机推荐
- Unity3D 跨平台原理
Unity3D的跨平台原理核心在于对指令集CIL(通用中间语言)的应用. 机理 首先需要知道,Unity中的Mono是基于 通用语言架构(Common Language Infrastructure, ...
- SpringCloud--1--服务治理Eureka
一.Eureka概述 1.Eureka特点 只需通过简单引入依赖和注解配置,就能让SpringBoot构建的微服务应用轻松地与Eureka服务治理体系进行整合. Eureka负责服务治理,即:微服务实 ...
- Mac 磁盘分区格式
Mac 磁盘分区格式 来源 https://www.chadou.me/p/190 参考文章 macOS磁盘工具帮助 在Mac系统中抹掉(格式化)磁盘的时候,要求选择分区方案,包括GUID分区图.主引 ...
- Nginx四个作用
本文只针对Nginx在不加载第三方模块的情况能处理哪些事情,由于第三方模块太多所以也介绍不完. Nginx能做什么 ——反向代理 ——负载均衡 ——HTTP服务器(动静分离) ——正向代理 以上就是我 ...
- JAVA基础之ServletContext应用
创建一个登陆的界面,并且统计次数! 导入jar包; 1. driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/java0603?u ...
- Java 之 Stream 流
Stream流 在Java 8中,得益于Lambda所带来的函数式编程,引入了一个全新的Stream概念,用于解决已有集合类库既有的弊端 一.传统遍历 1.传统集合的多步遍历代码 几乎所有的集合(如 ...
- 笔谈OpenGL ES(二)
昨晚回家也看了OpenGL ES 2.0 iOS教程的第一篇,对于其中涉及的一些基本知识罗列下,虽然自己做iOS开发一年多了,但是对于一些细节没有注意,真正的把自己当成“应用”工程师了 ,不仅要会用, ...
- java设计模式--观察者模式和事件监听器模式
观察者模式 观察者模式又称为订阅—发布模式,在此模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知.这通常透过呼叫各观察者所提供的方法来实现.此种模式通常被用来事件 ...
- git小结-ms
目录 1.git是什么 2.git怎么工作的 3.git常用命令 4.git提效工具 5.git的技术用语 1.git是什么 git是开源的分布式的版本控制系统,可以有效.高速地处理的项目版本管理.g ...
- Apache 安装后Error 403的故障排错方法(linux)
Apache 安装后Error 403的故障排错方法 2018年01月07日 14:25:41 个人分类: Linux 一.问题描述 在apache2的httpd配置中,很多情况都会出现403. 刚安 ...