go-embedxgo embed 的功能扩展

联合创作 · 2023-09-30 19:32

go1.16 //go:embed 的功能扩展。

简介:

go1.16 官方推出了go:embed 这个非常有意思的功能,可以嵌入静态文件到一个可执行文件中,发布软件时,只需要发布软件的可执行程序就可以了,不需要另外发布那些静态文件。之前这部分功能需要三方脚手架处理,比如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

该项目需要的静态文件存放在assets/schema.tl 目录中,需要把这个目录的所有文件都嵌入到最终的可执行程序中,可以这样做(assets/assets.go):

// Copyright 2020 Michael Li <alimy@gility.net>. 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目录中的静态文件(main.go):

// Copyright 2020 Michael Li <alimy@gility.net>. 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

// 预想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")
}
```

 

浏览 2
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

编辑 分享
举报