您好,欢迎访问一九零五行业门户网

embed是啥?Go怎么用它加载静态文件?

本文由go语言教程栏目给大家介绍golang1.16怎么使用embed加载静态文件 ,希望对需要的朋友有所帮助!
embed是什么
embed是在go 1.16中新加入的包。它通过//go:embed指令,可以在编译阶段将静态资源文件打包进编译好的程序中,并提供访问这些文件的能力。
为什么需要embed
在以前,很多从其他语言转过来go语言的小伙伴会问到,或者踩到一个坑:就是以为go语言所打包的二进制文件中会包含配置文件的联同编译和打包。
结果往往一把二进制文件挪来挪去,就无法把应用程序运行起来了,因为无法读取到静态文件的资源。
无法将静态资源编译打包二进制文件的话,通常会有两种解决方法:
第一种是识别这类静态资源,是否需要跟着程序走。第二种就是将其打包进二进制文件中。第二种情况的话,go以前是不支持的,大家就会借助各种花式的开源库,例如:go-bindata/go-bindata来实现。
但是在go1.16起,go语言自身正式支持了该项特性。
它有以下优点
能够将静态资源打包到二进制包中,部署过程更简单。传统部署要么需要将静态资源与已编译程序打包在一起上传,或者使用docker和dockerfile自动化前者,这是很麻烦的。确保程序的完整性。在运行过程中损坏或丢失静态资源通常会影响程序的正常运行。静态资源访问没有io操作,速度会非常快。embed基础用法通过 官方文档 我们知道embed嵌入的三种方式:string、bytes 和 fs(file systems)。其中string和[]byte类型都只能匹配一个文件,如果要匹配多个文件或者一个目录,就要使用embed.fs类型。
特别注意:embed这个包一定要导入,如果导入不使用的话,使用 _ 导入即可
一、嵌入为字符串比如当前文件下有个hello.txt的文件,文件内容为hello,world!。通过go:embed指令,在编译后下面程序中的s变量的值就变为了hello,world!。
package mainimport (    _ embed    fmt)//go:embed hello.txtvar s stringfunc main() {    fmt.println(s)}
二、嵌入为byte slice你还可以把单个文件的内容嵌入为slice of byte,也就是一个字节数组。
package mainimport (    _ embed    fmt)//go:embed hello.txtvar b []bytefunc main() {    fmt.println(b)}
三、嵌入为fs.fs甚至你可以嵌入为一个文件系统,这在嵌入多个文件的时候非常有用。
比如嵌入一个文件:
package mainimport (    embed    fmt)//go:embed hello.txtvar f embed.fsfunc main() {    data, _ := f.readfile(hello.txt)    fmt.println(string(data))}
嵌入本地的另外一个文件hello2.txt, 支持同一个变量上多个go:embed指令(嵌入为string或者byte slice是不能有多个go:embed指令的):
package mainimport (    embed    fmt)//go:embed hello.txt//go:embed hello2.txtvar f embed.fsfunc main() {    data, _ := f.readfile(hello.txt)    fmt.println(string(data))    data, _ = f.readfile(hello2.txt)    fmt.println(string(data))}

当前重复的go:embed指令嵌入为embed.fs是支持的,相当于一个:
package mainimport (    embed    fmt)//go:embed hello.txt//go:embed hello.txtvar f embed.fsfunc main() {    data, _ := f.readfile(hello.txt)    fmt.println(string(data))}
还可以嵌入子文件夹下的文件:
package mainimport (    embed    fmt)//go:embed p/hello.txt//go:embed p/hello2.txtvar f embed.fsfunc main() {    data, _ := f.readfile(p/hello.txt)    fmt.println(string(data))    data, _ = f.readfile(p/hello2.txt)    fmt.println(string(data))}
embed进阶用法go1.16 为了对 embed 的支持也添加了一个新包 io/fs。两者结合起来可以像之前操作普通文件一样。
一、只读嵌入的内容是只读的。也就是在编译期嵌入文件的内容是什么,那么在运行时的内容也就是什么。
fs文件系统值提供了打开和读取的方法,并没有write的方法,也就是说fs实例是线程安全的,多个goroutine可以并发使用。
embed.fs结构主要有3个对外方法,如下:
// open 打开要读取的文件,并返回文件的fs.file结构.func (f fs) open(name string) (fs.file, error)// readdir 读取并返回整个命名目录func (f fs) readdir(name string) ([]fs.direntry, error)// readfile 读取并返回name文件的内容.func (f fs) readfile(name string) ([]byte, error)
二、嵌入多个文件package mainimport (    embed    fmt)//go:embed hello.txt hello2.txtvar f embed.fsfunc main() {    data, _ := f.readfile(hello.txt)    fmt.println(string(data))    data, _ = f.readfile(hello2.txt)    fmt.println(string(data))}
当然你也可以像前面的例子一样写成多行go:embed:
package mainimport (    embed    fmt)//go:embed hello.txt//go:embed hello2.txtvar f embed.fsfunc main() {    data, _ := f.readfile(hello.txt)    fmt.println(string(data))    data, _ = f.readfile(hello2.txt)    fmt.println(string(data))}

三、支持文件夹文件夹分隔符采用正斜杠/,即使是windows系统也采用这个模式。
package mainimport (    embed    fmt)//go:embed pvar f embed.fsfunc main() {    data, _ := f.readfile(p/hello.txt)    fmt.println(string(data))    data, _ = f.readfile(p/hello2.txt)    fmt.println(string(data))}
应用在我们的项目中,是将应用的常用的一些配置写在了.env的一个文件上,所以我们在这里就可以使用go:embed指令。
main.go 文件:
//go:embed .env v1d0/.envvar fs embed.fsfunc main(){    setting.initsetting(fs)    manager.initmanager()    cron.initcron()    routersinit := routers.initrouter()    readtimeout := setting.serversetting.readtimeout    writetimeout := setting.serversetting.writetimeout    endpoint := fmt.sprintf(:%d, setting.serversetting.httpport)    maxheaderbytes := 1 << 20    server := &http.server{        addr:           endpoint,        handler:        routersinit,        readtimeout:    readtimeout,        writetimeout:   writetimeout,        maxheaderbytes: maxheaderbytes,    }    server.listenandserve()}
setting.go文件:
func initsetting(fs embed.fs) {    // 总配置处理    var err error    data, err := fs.readfile(.env)    if err != nil {        log.fatalf(fail to parse '.env': %v, err)    }    cfg, err = ini.load(data)    if err != nil {        log.fatal(err)    }    mapto(server, serversetting)    serversetting.readtimeout  = serversetting.readtimeout * time.second    serversetting.writetimeout = serversetting.writetimeout * time.second    // 分版本配置引入    v1d0setting.initsetting(fs)}
以上就是embed是啥?go怎么用它加载静态文件?的详细内容。
其它类似信息

推荐信息