go-embedxgo embed 的功能擴展
go1.16 //go:embed 的功能擴展。
簡介:
go1.16 官方推出了go:embed 這個非常有意思的功能,可以嵌入靜態(tài)文件到一個可執(zhí)行文件中,發(fā)布軟件時,只需要發(fā)布軟件的可執(zhí)行程序就可以了,不需要另外發(fā)布那些靜態(tài)文件。之前這部分功能需要三方腳手架處理,比如go-bindata,go1.16開始,直接在go的工具鏈中提供了go:embed支持完成相同的工作,使用體驗非常的nice。
具體使用示例可以參考tl-explorer:
%> git clone --recursive https://github.com/alimy/tl-explorer
%> cd tl-explorer && pwd
go/src/github.com/alimy/tl-explorer
%> tree -L 2
.
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── assets
│ ├── assets.go
│ └── schema.tl
├── go.mod
├── go.sum
├── main.go
└── scripts
├── launchd
└── systemd
該項目需要的靜態(tài)文件存放在assets/schema.tl 目錄中,需要把這個目錄的所有文件都嵌入到最終的可執(zhí)行程序中,可以這樣做(assets/assets.go):
// Copyright 2020 Michael Li <[email protected]>. All rights reserved.
// Use of this source code is governed by Apache License 2.0 that
// can be found in the LICENSE file.
package assets
import (
"embed"
"net/http"
"github.com/alimy/embedx"
)
// NewFileSystem get an assets http.FileSystem instance
func NewFileSystem() http.FileSystem {
//go:embed schema.tl
var content embed.FS
embedFS := embedx.ChangeRoot(content, "schema.tl")
return http.FS(embedFS)
}
聲明需要嵌入的那些文件,然后在程序中就可以通過embed.FS訪問這些文件,如例子中:
//go:embed schema.tl
var content embed.FS
通過embed.FS訪問schema.tl中的文件。
我們這里通過http server訪問schema.tl目錄中的靜態(tài)文件(main.go):
// Copyright 2020 Michael Li <[email protected]>. All rights reserved.
// Use of this source code is governed by Apache License 2.0 that
// can be found in the LICENSE file.
package main
import (
"flag"
"fmt"
"log"
"net/http"
"github.com/alimy/tl-explorer/assets"
)
var (
host string
port uint
showVersion bool
version = "v0.2.0"
)
func init() {
flag.StringVar(&host, "host", "", "listening host")
flag.UintVar(&port, "port", 8080, "listening port")
flag.BoolVar(&showVersion, "v", false, "show version")
}
func main() {
flag.Parse()
if showVersion {
fmt.Println(version)
return
}
addr := fmt.Sprintf("%s:%d", host, port)
if host == "" {
host = "localhost"
}
fmt.Printf("listening in [%s]. Please open http://%s:%d in browser to enjoy yourself.\n", addr, host, port)
http.Handle("/", http.FileServer(assets.NewFileSystem()))
if err := http.ListenAndServe(addr, nil); err != nil {
log.Fatal(err)
}
}
官方的go:embed使用體驗非常好,那有沒有其他限制呢?有的,比如上面例子,我們嵌入了schema.tl目錄,那么通過embed.FS 訪問schema.tl目錄下的文件比如index.html時,需要這樣訪問:
//go:embed schema.tl
var content embed.FS
indexContent, _ := content.ReadFile("schema.tl/index.html")
我其實是想把schema.tl目錄作為根目錄,訪問目錄下的文件時,就如當前就在根目錄下訪問文件,不需要加schema.tl目錄名前綴:
//go:embed schema.tl
var content embed.FS
// 預(yù)想schema.tl為根目錄, 訪問shema.tl/index.html, 只給定文件名index.html即可
// indexContent, _ := content.ReadFile("index.html")
go-embedx提供這樣的輔助功能特性,這里可以使用輔助庫的 ‘改變root目錄’ 功能,使用如下:
//go:embed schema.tl
var content embed.FS
// 改變根目錄為shema.tl目錄
embedFS := embedx.ChangeRoot(content, "schema.tl")
// 訪問schema.tl目錄下的index.html,可以這樣做
indexContent, _ := embedFS.ReadFile("index.html")
fmt.Println(indexContent)
go-embedx還提供其他輔助功能,比如為embed.FS 附加一個虛擬根目錄等。
使用實例:
%> cd demo # change to your golang project root directory; cd <your-project-dir>
%> go get github.com/alimy/embedx
%> tree
|- public
|- ...
|- index.html
|- ...
|- conf
|- app.ini
|- ...
|- conf.go
|- ...
|- main.go
|- go.mod
|- ...
%> cat conf/conf.go
// file: conf/conf.go
package conf
import (
"embed"
"github.com/alimy/embedx"
)
func NewConfigFS() embedx.EmbedFS {
//go:embed app.ini
var content embed.FS
// attach a root to conf dir then access files in this returned FS will
// need add 'conf' prefix. eg: access app.ini need FS.ReadFile("conf/app.ini").
return embedx.AttachRoot(content, "conf")
}
%> cat main.go
// file: main.go
package main
import (
"embed"
"github.com/alimy/embedx"
)
func newPublicFS() embedx.EmbedFS {
//go:embed public
var content embed.FS
// change the root to public dir then access files in this returned FS will
// not need 'public' prefix. eg: access public/index.html just need FS.ReadFile("index.html").
return embedx.ChangeRoot(content, "public")
}
```
評論
圖片
表情
