提前试用将在 Go1.16 中发布的内嵌静态资源功能( 二 )
结果和 Echo 框架一样 。 同样要注意是 /*filepath , 不能是 / 。
换成标准库 net/http 试试?
package mainimport ("embed""log""net/http")//go:embed staticvar local embed.FSfunc main() {http.Handle("/", http.FileServer(http.FS(local)))log.Fatal(http.ListenAndServe(":8989", nil))}
标准库中 / 会自动处理所有的请求 。
02 //go:embed 指令之前第三方的现实 , 基本是基于 go generate , 将静态资源文件生成 go 源文件 , 最后编译进二进制文件中 。 官方的实现 , 通过 //go:embed 指令 , 在编译时将静态资源嵌入二进制文件中 。 然后 , Go 通过标准库 , 让用户能够访问这些内嵌的资源 。 因此 , 先介绍下 //go:embed 指令的用法 。
相关规则在变量声明上方 , 通过 //go:embed 指令指定一个或多个符合 path.Match 模式的要嵌入的文件或目录 。 相关规则或使用注意如下:
1)跟其他指令一样 , // 和 go:embed 之间不能有空格 。 (不会报错 , 但该指令会被编译器忽略)
2)指令和变量声明之间可以有空行或普通注释 , 不能有其他语句;
//go:embed message.txtvar message string
以上代码是允许的 , 不过建议紧挨着 , 而且建议变量声明和指令之间也别加注释 , 注释应该放在指令上方 。
3)变量的类型只能是 string、[]byte 或 embed.FS , 即使是这三个类型的别名也不行;
type mystring = string//go:embed hello.txtvar message mystring // 编译不通过:go:embed cannot apply to var of type mystring
4)允许有多个 //go:embed 指令 。 多个文件或目录可以通过空格分隔 , 也可以写多个指令 。 比如:
//go:embed image template//go:embed html/index.htmlvar content embed.FS
5)文件或目录使用的是相对路径 , 相对于指令所在 Go 源文件所在的目录 , 路径分隔符永远使用 /;当文件或目录名包含空格时 , 可以使用双引号或反引号括起来 。
6)对于目录 , 会以该目录为根 , 递归的方式嵌入所有文件和子目录;
7)变量的声明可以是导出或非导出的;可以是全局也可以在函数内部;但只能是声明 , 不能给初始化值;
//go:embed message.txtvar message string = "" // 编译不通过:go:embed cannot apply to var with initializer
8)只能内嵌模块内的文件 , 比如 .git/* 或软链接文件无法匹配;空目录会被忽略;
9)模式不能包含 . 或 .. , 也不能以 / 开始 , 如果要匹配当前目录所有文件 , 应该使用 * 而不是 .;
03 标准库和 embed 相关的标准库有 5 个 , 其中 2 个是新增的:embed 和 io/fs;net/http , text/template 和 html/template 包依赖 io/fs 包 , 而 embed.FS 类型实现了 io/fs 包的 FS 接口 , 因此这 3 个包可以使用 embed.FS 。 (Go1.16 发布时可能还会增加其他包或修改一些包的内容)
io/fs 包该包定义了文件系统的基本接口 。 文件系统既可以由主机操作系统提供 , 也可以由其他包提供 。 本文我们主要介绍和 embed 密切相关的内容 。
先看 FS 接口:
type FS interface {// Open opens the named file.//// When Open returns an error, it should be of type *PathError// with the Op field set to "open", the Path field set to name,// and the Err field describing the problem.//// Open should reject attempts to open names that do not satisfy// ValidPath(name), returning a *PathError with Err set to// ErrInvalid or ErrNotExist.Open(name string) (File, error)}
FS 提供对分层文件系统的访问 。 像操作系统使用的文件系统就是一种分层文件系统 。
FS 接口是文件系统所需的最小实现 。 文件系统可以实现其他接口 , 比如 fs.ReadFileFS , 以提供其他或优化的功能 。
File 接口:
【提前试用将在 Go1.16 中发布的内嵌静态资源功能】type File interface {Stat() (FileInfo, error)Read([]byte) (int, error)Close() error}
该接口定义对单个文件的访问 。 这是文件的最小实现要求 。 文件可以实现其他接口 , 例如 fs.ReadDirFile , io.ReaderAt 或 io.Seeker , 以提供其他或优化的功能 。
因为有了 FS、File 等的接口抽象 , 之前在 os 包中的一些内容移到了 io/fs 包中 , 比如 fs.FileInfo 接口、fs.FileMode 类型 , os 中原有的定义改成了它们的别名 。
DirEntry 接口:
type DirEntry interface {// Name returns the name of the file (or subdirectory) described by the entry.// This name is only the final element of the path (the base name), not the entire path.// For example, Name would return "hello.go" not "/home/gopher/hello.go".Name() string// IsDir reports whether the entry describes a directory.IsDir() bool// Type returns the type bits for the entry.// The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method.Type() FileMode// Info returns the FileInfo for the file or subdirectory described by the entry.// The returned FileInfo may be from the time of the original directory read// or from the time of the call to Info. If the file has been removed or renamed// since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist).// If the entry denotes a symbolic link, Info reports the information about the link itself,// not the link's target.Info() (FileInfo, error)}
- 空调|让格力、海尔都担忧,中国取暖“新潮物”强势来袭,空调将成闲置品?
- 采用|消息称一加9系列将推出三款新机,新增一加9E
- 美国|英国媒体惊叹:165个国家采用北斗将GPS替代,连美国也不例外?
- 通气会|12月4~6日,2020中国信息通信大会将在成都举行
- 黑莓(BB.US)盘前涨逾32%,将与亚马逊开发智能汽车数据平台|美股异动 | US
- 荣耀V30|麒麟990+40W快充,昔日猛将彻底沦为清仓价?网友:太遗憾
- 网络覆盖|爱立信:2020年底,将有超过10亿人口获得5G网络覆盖
- 砍单|iPhone12之后,拼多多又将iPhone12Pro拉下水
- 短视频平台|大数据佐证,抖音带动三千万就业,视频手机将成生产力工具?
- 社区团购|你在买菜APP上薅的每一根羊毛,都将加倍奉还!