0

0

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

藏色散人

藏色散人

发布时间:2021-11-12 14:31:44

|

4502人浏览过

|

来源于learnku

转载

本文由go语言教程栏目给大家介绍golang1.16怎么使用embed加载静态文件 ,希望对需要的朋友有所帮助!

embed是什么

embed是在Go 1.16中新加入的包。它通过//go:embed指令,可以在编译阶段将静态资源文件打包进编译好的程序中,并提供访问这些文件的能力。

为什么需要embed

在以前,很多从其他语言转过来Go语言的小伙伴会问到,或者踩到一个坑:就是以为Go语言所打包的二进制文件中会包含配置文件的联同编译和打包。

结果往往一把二进制文件挪来挪去,就无法把应用程序运行起来了,因为无法读取到静态文件的资源。

无法将静态资源编译打包二进制文件的话,通常会有两种解决方法:

  • 第一种是识别这类静态资源,是否需要跟着程序走。
  • 第二种就是将其打包进二进制文件中。

第二种情况的话,Go以前是不支持的,大家就会借助各种花式的开源库,例如:go-bindata/go-bindata来实现。

但是在Go1.16起,Go语言自身正式支持了该项特性。

它有以下优点

  • 能够将静态资源打包到二进制包中,部署过程更简单。传统部署要么需要将静态资源与已编译程序打包在一起上传,或者使用dockerdockerfile自动化前者,这是很麻烦的。
  • 确保程序的完整性。在运行过程中损坏或丢失静态资源通常会影响程序的正常运行。
  • 静态资源访问没有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


甚至你可以嵌入为一个文件系统,这在嵌入多个文件的时候非常有用。

比如嵌入一个文件:

Lyrics Generator
Lyrics Generator

免费人工智能歌词生成器和人工智能歌曲作家

下载
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/.env"var 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)}

相关专题

更多
高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

65

2026.01.16

全民K歌得高分教程大全
全民K歌得高分教程大全

本专题整合了全民K歌得高分技巧汇总,阅读专题下面的文章了解更多详细内容。

123

2026.01.16

C++ 单元测试与代码质量保障
C++ 单元测试与代码质量保障

本专题系统讲解 C++ 在单元测试与代码质量保障方面的实战方法,包括测试驱动开发理念、Google Test/Google Mock 的使用、测试用例设计、边界条件验证、持续集成中的自动化测试流程,以及常见代码质量问题的发现与修复。通过工程化示例,帮助开发者建立 可测试、可维护、高质量的 C++ 项目体系。

33

2026.01.16

java数据库连接教程大全
java数据库连接教程大全

本专题整合了java数据库连接相关教程,阅读专题下面的文章了解更多详细内容。

39

2026.01.15

Java音频处理教程汇总
Java音频处理教程汇总

本专题整合了java音频处理教程大全,阅读专题下面的文章了解更多详细内容。

19

2026.01.15

windows查看wifi密码教程大全
windows查看wifi密码教程大全

本专题整合了windows查看wifi密码教程大全,阅读专题下面的文章了解更多详细内容。

85

2026.01.15

浏览器缓存清理方法汇总
浏览器缓存清理方法汇总

本专题整合了浏览器缓存清理教程汇总,阅读专题下面的文章了解更多详细内容。

20

2026.01.15

ps图片相关教程汇总
ps图片相关教程汇总

本专题整合了ps图片设置相关教程合集,阅读专题下面的文章了解更多详细内容。

11

2026.01.15

ppt一键生成相关合集
ppt一键生成相关合集

本专题整合了ppt一键生成相关教程汇总,阅读专题下面的的文章了解更多详细内容。

47

2026.01.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
golang socket 编程
golang socket 编程

共2课时 | 0.1万人学习

nginx浅谈
nginx浅谈

共15课时 | 0.8万人学习

golang和swoole核心底层分析
golang和swoole核心底层分析

共3课时 | 0.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号