在go语言里面,我们可以使用一个“类注释”的语法来来让编译器帮助我们在编译的时候将一些文件或者目录读取到指定的变量中来供我们使用。
go:embed语法:
//go:embed 文件或者目录路径
var 变量名 变量类型
说明:
文件或者目录路径 可以是相对路径,也可以是绝对路径,路径中可以使用通配符*来指定要加载的文件类型,这个的用法和 filepath.Glob(pattern string)函数的用法是一样的.
变量类型 这里只支持2种变量类型 string 或者 embed.FS , 这个embed.FS是一个结构体,专门用来接收文件集合的,注意是只读文件集合。
使用示例
在下面的示例中我们定义了2个全局变量: MyAbc用来接收abc.txt中的内容; MyStaticFs用来接收statics文件夹下的html文件信息。 在 fs_test.go文件中,我们演示了如何使用我们定义的预编译变量,和如何将 embed.FS类型转换为 http.FileSystem 以及创建一个简单的静态服务示例。
假设我们的文件目录结构如下
├── abc.txt
├── fs.go
├── main.go
└── statics
└── index.html
abc.txt 的文件内容
abc123
fs.go 这个是我们的//go:embed的预编译定义
package main
import (
"embed"
)
//go:embed abc.txt
var MyAbc string
//go:embed statics/*.html
var MyStaticFs embed.FS
fs_test.go使用示例
package main
import (
"fmt"
"net/http"
"testing"
)
func TestDemo(t *testing.T) {
abc := MyAbc
// 使用预编译的变量
fmt.Println("预编译变量MyAbc的内容为:", abc) // abc123
// 这里我们就可以直接使用我们定义的预编译变量了, 他的类型是 embed.FS
statics := MyStaticFs
// 创建一个静态文件服务的handler 注意这里使用的是FileServerFS
// handler := http.FileServerFS(statics)
// 如果要是哟共 FileServer 则需要将类型embed.FS转换为http.FileSystem
staticsFs := http.FS(statics)
handler := http.FileServer(staticsFs)
http.ListenAndServe(":8000", handler)
}
运行内存图解和总结
通过上面的图示,我们可以看到,编译器将文件abc.txt的内容读取并赋值给了我们定义的变量MyAbc, 将文件夹 statics 中的html文件和文件夹自己放入到了我们定义的 embed.FS 类型变量 MyStaticFs里面, 在这个变量里面包含了我们定义的文件的名称完整内容和文件hash等信息,可见go是吧我们指定的文件夹下面的所有文件内容都读取到了FS变量里面了,所以这个地方建议只放小文件,大文件千万别用这种模式来操作!!!
embed.FS只读文件集合结构体定义参考:
这个里面详情阐述了FS结构体的用法和 文件模式的用法。
// An FS is a read-only collection of files, usually initialized with a //go:embed directive.
// When declared without a //go:embed directive, an FS is an empty file system.
//
// An FS is a read-only value, so it is safe to use from multiple goroutines
// simultaneously and also safe to assign values of type FS to each other.
//
// FS implements fs.FS, so it can be used with any package that understands
// file system interfaces, including net/http, text/template, and html/template.
//
// See the package documentation for more details about initializing an FS.
type FS struct {
// The compiler knows the layout of this struct.
// See cmd/compile/internal/staticdata's WriteEmbed.
//
// The files list is sorted by name but not by simple string comparison.
// Instead, each file's name takes the form "dir/elem" or "dir/elem/".
// The optional trailing slash indicates that the file is itself a directory.
// The files list is sorted first by dir (if dir is missing, it is taken to be ".")
// and then by base, so this list of files:
//
// p
// q/
// q/r
// q/s/
// q/s/t
// q/s/u
// q/v
// w
//
// is actually sorted as:
//
// p # dir=. elem=p
// q/ # dir=. elem=q
// w/ # dir=. elem=w
// q/r # dir=q elem=r
// q/s/ # dir=q elem=s
// q/v # dir=q elem=v
// q/s/t # dir=q/s elem=t
// q/s/u # dir=q/s elem=u
//
// This order brings directory contents together in contiguous sections
// of the list, allowing a directory read to use binary search to find
// the relevant sequence of entries.
files *[]file
}