内容简介:对于 Go 语言开发者来说,在享受语言便利性的同时,最终编译的单一可执行文件也是我们所热衷的。但是,Go在编译成二进制文件时并没有把我们的静态资源文件编译进去,如果我们开发的是web应用的话就需要想办法把我们的静态文件也编译进去。本文收集了一些Go语言中用来在编译过程中将静态文件打包到编译文件的方法。
对于 Go 语言开发者来说,在享受语言便利性的同时,最终编译的单一可执行文件也是我们所热衷的。
但是,Go在编译成二进制文件时并没有把我们的静态资源文件编译进去,如果我们开发的是web应用的话就需要想办法把我们的静态文件也编译进去。
本文收集了一些Go语言中用来在编译过程中将静态文件打包到编译文件的方法。
go-bindata
在 Go 语言的 Awesome 中你可以看到很多静态打包库,但是,你却看不到 go-bindata, go-bindata 明显更受欢迎,更流行。
go-bindata 很简单,设计理念也不难理解。它的任务就是讲静态文件封装在一个 Go 语言的 Source Code 里面,然后提供一个统一的接口,你通过这个接口传入文件路径,它将给你返回对应路径的文件数据。这也就是说它不在乎你的文件是字符型的文件还是字节型的,你自己处理,它只管包装。
简单来说就是它可以把我们的静态文件生成 .go
文件,这样就可以编译成二进制文件,项目启动的时候再把这个 .go
文件再释放成静态文件
使用
打包整个静态目录,使用的时候释放
# 目录结构
ConfigTest
├── asset
│ └── asset.go 静态文件编译之后的go文件
├── config # 静态文件目录
│ ├── rule.yaml
│ └── rule.json
├── cli # 运行目录
│ ├── config 执行main释放出来的静态文件
│ │ ├── rule.yaml
│ │ └── rule.json
│ └── main # main.go编译之后生成的二进制执行文件
└── main 程序目录
└── main.go # 源码
执行命令将静态文件打包成go文件
go-bindata -o=./asset/asset.go -pkg=asset config/... -o # 指定打包后生成的go文件路径 -pkg # 指定go文件的包名 config/... # 指定需要打包的静态文件路径
main函数中解压静态文件
package main
import "ConfigTest/asset"
func main() {
dirs := []string{"config"} // 设置需要释放的目录
for _, dir := range dirs {
// 解压dir目录到当前目录
if err := asset.RestoreAssets("./", dir); err != nil {
break
}
}
}
编译 main.go
执行二进制文件
cd cli && go build ../main/main.go ./main # 执行之后会自动解压出config目录以及下面的静态文件
使用
目录结构
ConfigTest
├── asset
│ └── asset.go 静态文件编译之后的go文件
├── cli # 运行目录
│ ├── config
│ │ ├── config.json
│ │ └── config.yaml
│ └── main # main.go编译之后生成的二进制执行文件
├── config # 配置文件目录
│ ├── config.json
│ └── config.yaml
└── main # 程序目录
└── main.go # 源码
yaml配置文件内容
enabled: true path: aaaaa id: 10
json文件内容
{
"enabled": true,
"path": "xxxx",
"id": 111
}
main.go
package main
import (
"ConfigTest/asset"
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
yaml "gopkg.in/yaml.v2"
)
type conf struct {
Enabled bool
Path string
ID int
}
func (c *conf) ReadYaml() {
data, _ := asset.Asset("config/config.yaml")
err := yaml.Unmarshal(data, &c)
if err != nil {
log.Fatalf("Unmarshal: %v", err)
}
}
func (c *conf) ReadJson() {
data, _ := asset.Asset("config/config.json")
err := json.Unmarshal(data, &c)
if err != nil {
log.Fatalf("Unmarshal: %v", err)
}
}
func restore() {
dirs := []string{"config"} // 设置需要释放的目录
isSuccess := true
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))
}
}
}
func main() {
var c, j conf
j.ReadJson()
fmt.Println("json:", j)
c.ReadYaml()
fmt.Println("yaml:", c)
fmt.Println("释放静态文件")
restore()
}
执行命令将静态文件打包成go文件
go-bindata -o=./asset/asset.go -pkg=asset config/... -o # 指定打包后生成的go文件路径 -pkg # 指定go文件的包名 config/... # 指定需要打包的静态文件路径
编译 main.go
执行二进制文件
cd cli && go build ../main/main.go
./main
json: {true xxxx 111}
yaml: {true aaaaa 10}
释放静态文件
# 执行之后会自动解压出config目录以及下面的静态文件
http.FileSystem
http.FileSystem
是定义 HTTP 静态文件服务的接口。 go-bindata
的第三方包 go-bindata-assetfs
实现了这个接口,支持 HTTP 访问静态文件目录的行为。
// import (
// "net/http"
// "github.com/elazarl/go-bindata-assetfs"
// "github.com/go-xiaohei/pugo/app/asset" // 用 pugo 的asset.go进行测试
// )
func myhttp() {
fs := assetfs.AssetFS{
Asset: asset.Asset,
AssetDir: asset.AssetDir,
AssetInfo: asset.AssetInfo,
}
http.Handle("/", http.FileServer(&fs))
http.ListenAndServe(":12345", nil)
}
func main() {
myhttp()
}
访问 http://localhost:12345
,就可以看到嵌入的静态资源目录的内容了
go.rice
go.rice
也支持打包静态文件到 go 文件中,但是行为和 go-bindata
很不相同。从使用角度, go.rice
其实是更便捷的静态文件操作库。打包静态文件反而是顺带的功能。
安装
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)
}
命令
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 工具也这两个主要功能。
安装
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/...
// ......
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 多页应用增量更新静态资源Webpack打包方案
- Webpack4 学习笔记 - 03:loader 打包静态资源(样式)
- 详解vue静态资源打包中的坑与解决方案
- 小程序静态资源无缝转移到腾讯云COS 使用wepy mpvue 等webpack打包的小程序项目
- 静态库遇到静态库
- 全局变量,静态全局变量,局部变量,静态局部变量
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
An Introduction to the Analysis of Algorithms
Robert Sedgewick、Philippe Flajolet / Addison-Wesley Professional / 1995-12-10 / CAD 67.99
This book is a thorough overview of the primary techniques and models used in the mathematical analysis of algorithms. The first half of the book draws upon classical mathematical material from discre......一起来看看 《An Introduction to the Analysis of Algorithms》 这本书的介绍吧!