Go embed 简明教程_会飞的胖达喵的博客-CSDN博客


本站和网页 https://blog.csdn.net/lengyue1084/article/details/123750900 的作者无关,不对其内容负责。快照谨为网络故障时之索引,不代表被搜索网站的即时页面。

Go embed 简明教程_会飞的胖达喵的博客-CSDN博客
Go embed 简明教程
会飞的胖达喵
于 2022-03-26 09:55:49 发布
2840
收藏
分类专栏:
golang
文章标签:
embed
原文链接:https://colobu.com/2021/01/17/go-embed-tutorial/
版权
golang
专栏收录该内容
198 篇文章
11 订阅
订阅专栏
转载地址:Go embed 简明教程
Go编译的程序非常适合部署,如果没有通过CGO引用其它的库的话,我们一般编译出来的可执行二进制文件都是单个的文件,非常适合复制和部署。在实际使用中,除了二进制文件,可能还需要一些配置文件,或者静态文件,比如html模板、静态的图片、CSS、javascript等文件,如何这些文件也能打进到二进制文件中,那就太美妙,我们只需复制、按照单个的可执行文件即可。
一些开源的项目很久以前就开始做这方面的工作,比如gobuffalo/packr、markbates/pkger、rakyll/statik、knadh/stuffbin等等,但是不管怎么说这些都是第三方提供的功能,如果Go官方能内建支持就好了。2019末一个提案被提出issue#35950,期望Go官方编译器支持嵌入静态文件。后来Russ Cox专门写了一个设计文档Go command support for embedded static assets, 并最终实现了它。
Go 1.16中包含了go embed的功能,而且Go1.16基本在一个月左右的时间就会发布了,到时候你可以尝试使用它,如果你等不及了,你也可以下载Go 1.16beta1尝鲜。
本文将通过例子,详细介绍go embed的各个功能。
嵌入
对于单个的文件,支持嵌入为字符串和 byte slice对于多个文件和文件夹,支持嵌入为新的文件系统FS比如导入 "embed"包,即使无显式的使用go:embed指令用来嵌入,必须紧跟着嵌入后的变量名只支持嵌入为string, byte slice和embed.FS三种类型,这三种类型的别名(alias)和命名类型(如type S string)都不可以
嵌入为字符串
比如当前文件下有个hello.txt的文件,文件内容为hello,world!。通过go:embed指令,在编译后下面程序中的s变量的值就变为了hello,world!。
package main import ( _ "embed" "fmt" ) //go:embed hello.txt var s string func main() { fmt.Println(s) }
嵌入为byte slice
你还可以把单个文件的内容嵌入为slice of byte,也就是一个字节数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 package main import ( _ "embed" "fmt" ) //go:embed hello.txt var b []byte func main() { fmt.Println(b) }
嵌入为fs.FS
甚至你可以嵌入为一个文件系统,这在嵌入多个文件的时候非常有用。 比如嵌入一个文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package main import ( "embed" "fmt" ) //go:embed hello.txt var f embed.FS func main() { data, _ := f.ReadFile("hello.txt") fmt.Println(string(data)) }
嵌入本地的另外一个文件hello2.txt, 支持同一个变量上多个go:embed指令(嵌入为string或者byte slice是不能有多个go:embed指令的):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package main import ( "embed" "fmt" ) //go:embed hello.txt //go:embed hello2.txt var f embed.FS func main() { data, _ := f.ReadFile("hello.txt") fmt.Println(string(data)) data, _ = f.ReadFile("hello2.txt") fmt.Println(string(data)) }
当前重复的go:embed指令嵌入为embed.FS是支持的,相当于一个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package main import ( "embed" "fmt" ) //go:embed hello.txt //go:embed hello.txt var f embed.FS func main() { data, _ := f.ReadFile("hello.txt") fmt.Println(string(data)) }
还可以嵌入子文件夹下的文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package main import ( "embed" "fmt" ) //go:embed p/hello.txt //go:embed p/hello2.txt var f embed.FS func main() { data, _ := f.ReadFile("p/hello.txt") fmt.Println(string(data)) data, _ = f.ReadFile("p/hello2.txt") fmt.Println(string(data)) }
还可以支持模式匹配的方式嵌入,下面的章节专门介绍。
同一个文件嵌入为多个变量
比如下面的例子,s和s2变量都嵌入hello.txt的文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package main import ( _ "embed" "fmt" ) //go:embed hello.txt var s string //go:embed hello.txt var s2 string func main() { fmt.Println(s) fmt.Println(s2) }
exported/unexported的变量都支持
Go可以将文件可以嵌入为exported的变量,也可以嵌入为unexported的变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package main import ( _ "embed" "fmt" ) //go:embed hello.txt var s string //go:embed hello2.txt var S string func main() { fmt.Println(s) fmt.Println(S) }
package级别的变量和局部变量都支持
前面的例子都是package一级的的变量,即使是函数内的局部变量,也都支持嵌入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package main import ( _ "embed" "fmt" ) func main() { //go:embed hello.txt var s string //go:embed hello.txt var s2 string fmt.Println(s, s2) }
局部变量s的值在编译时就已经嵌入了,而且虽然s和s2嵌入同一个文件,但是它们的值在编译的时候会使用初始化字段中的不同的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 0x0021 00033 (/Users/....../main.go:10) MOVQ "".embed.1(SB), AX 0x0028 00040 (/Users/....../main.go:10) MOVQ "".embed.1+8(SB), CX 0x002f 00047 (/Users/....../main.go:13) MOVQ "".embed.2(SB), DX 0x0036 00054 (/Users/....../main.go:13) MOVQ DX, "".s2.ptr+72(SP) 0x003b 00059 (/Users/....../main.go:13) MOVQ "".embed.2+8(SB), BX ...... "".embed.1 SDATA size=16 0x0000 00 00 00 00 00 00 00 00 0d 00 00 00 00 00 00 00 ................ rel 0+8 t=1 go.string."hello, world!"+0 "".embed.2 SDATA size=16 0x0000 00 00 00 00 00 00 00 00 0d 00 00 00 00 00 00 00 ................ rel 0+8 t=1 go.string."hello, world!"+0
注意s和s2的变量的值是在编译期就确定了,即使在运行时你更改了hello.txt的文件,甚至把hello.txt都删除了也不会改变和影响s和s2的值。
只读
嵌入的内容是只读的。也就是在编译期嵌入文件的内容是什么,那么在运行时的内容也就是什么。
FS文件系统值提供了打开和读取的方法,并没有write的方法,也就是说FS实例是线程安全的,多个goroutine可以并发使用。
1 2 3 4 type FS func (f FS) Open(name string) (fs.File, error) func (f FS) ReadDir(name string) ([]fs.DirEntry, error) func (f FS) ReadFile(name string) ([]byte, error)
go:embed指令
go:embed指令支持嵌入多个文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package main import ( "embed" "fmt" ) //go:embed hello.txt hello2.txt var f embed.FS func main() { data, _ := f.ReadFile("hello.txt") fmt.Println(string(data)) data, _ = f.ReadFile("hello2.txt") fmt.Println(string(data)) }
当然你也可以像前面的例子一样写成多行go:embed:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package main import ( "embed" "fmt" ) //go:embed hello.txt //go:embed hello2.txt var f embed.FS func main() { data, _ := f.ReadFile("hello.txt") fmt.Println(string(data)) data, _ = f.ReadFile("hello2.txt") fmt.Println(string(data)) }
支持文件夹
文件夹分隔符采用正斜杠/,即使是windows系统也采用这个模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package main import ( "embed" "fmt" ) //go:embed p var f embed.FS func main() { data, _ := f.ReadFile("p/hello.txt") fmt.Println(string(data)) data, _ = f.ReadFile("p/hello2.txt") fmt.Println(string(data)) }
使用的是相对路径
相对路径的根路径是go源文件所在的文件夹。
支持使用双引号"或者反引号的方式应用到嵌入的文件名或者文件夹名或者模式名上,这对名称中带空格或者特殊字符的文件文件夹有用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package main import ( "embed" "fmt" ) //go:embed "he llo.txt" `hello-2.txt` var f embed.FS func main() { data, _ := f.ReadFile("he llo.txt") fmt.Println(string(data)) }
匹配模式
go:embed指令中可以只写文件夹名,此文件夹中除了.和_开头的文件和文件夹都会被嵌入,并且子文件夹也会被递归的嵌入,形成一个此文件夹的文件系统。
如果想嵌入.和_开头的文件和文件夹, 比如p文件夹下的.hello.txt文件,那么就需要使用*,比如go:embed p/*。
*不具有递归性,所以子文件夹下的.和_不会被嵌入,除非你在专门使用子文件夹的*进行嵌入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package main import ( "embed" "fmt" ) //go:embed p/* var f embed.FS func main() { data, _ := f.ReadFile("p/.hello.txt") fmt.Println(string(data)) data, _ = f.ReadFile("p/q/.hi.txt") // 没有嵌入 p/q/.hi.txt fmt.Println(string(data)) }
嵌入和嵌入模式不支持绝对路径、不支持路径中包含.和..,如果想嵌入go源文件所在的路径,使用*:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package main import ( "embed" "fmt" ) //go:embed * var f embed.FS func main() { data, _ := f.ReadFile("hello.txt") fmt.Println(string(data)) data, _ = f.ReadFile(".hello.txt") fmt.Println(string(data)) }
文件系统
embed.FS实现了 io/fs.FS接口,它可以打开一个文件,返回fs.File:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package main import ( "embed" "fmt" ) //go:embed * var f embed.FS func main() { helloFile, _ := f.Open("hello.txt") stat, _ := helloFile.Stat() fmt.Println(stat.Name(), stat.Size()) }
它还提供了ReadFileh和ReadDir功能,遍历一个文件下的文件和文件夹信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 package main import ( "embed" "fmt" ) //go:embed * var f embed.FS func main() { dirEntries, _ := f.ReadDir("p") for _, de := range dirEntries { fmt.Println(de.Name(), de.IsDir()) } }
因为它实现了io/fs.FS接口,所以可以返回它的子文件夹作为新的文件系统:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package main import ( "embed" "fmt" "io/fs" "io/ioutil" ) //go:embed * var f embed.FS func main() { ps, _ := fs.Sub(f, "p") hi, _ := ps.Open("q/hi.txt") data, _ := ioutil.ReadAll(hi) fmt.Println(string(data)) }
应用
net/http
先前,我们提供一个静态文件的服务时,使用:
1 http.Handle("/", http.FileServer(http.Dir("/tmp")))
现在,io/fs.FS文件系统也可以转换成http.FileServer的参数了:
1 2 3 4 5 type FileSystem func FS(fsys fs.FS) FileSystem type Handler func FileServer(root FileSystem) Handler
所以,嵌入文件可以使用下面的方式:
1 http.Handle("/", http.FileServer(http.FS(fsys)))
text/template和html/template.
同样的,template也可以从嵌入的文件系统中解析模板:
1 2 func ParseFS(fsys fs.FS, patterns ...string) (*Template, error) func (t *Template) ParseFS(fsys fs.FS, patterns ...string) (*Template, error)
会飞的胖达喵
关注
关注
点赞
收藏
知道了
评论
Go embed 简明教程
转载地址:Go embed 简明教程Go编译的程序非常适合部署,如果没有通过CGO引用其它的库的话,我们一般编译出来的可执行二进制文件都是单个的文件,非常适合复制和部署。在实际使用中,除了二进制文件,可能还需要一些配置文件,或者静态文件,比如html模板、静态的图片、CSS、javascript等文件,如何这些文件也能打进到二进制文件中,那就太美妙,我们只需复制、按照单个的可执行文件即可。一些开源的项目很久以前就开始做这方面的工作,比如gobuffalo/packr、markbates/pkger、
复制链接
扫一扫
专栏目录
Go-go-embed-生成的Go代码来嵌入资源文件到你的库或可执行文件中
08-13
go-embed - 生成的Go代码来嵌入资源文件到你的库或可执行文件中
【Go语言】gin + go:embed 打包静态资源文件
Regulations的博客
02-02
277
【代码】【Go语言】gin + go:embed 打包静态资源文件。
参与评论
您还未登录,请先
登录
后发表或查看评论
Go-embed:另一个Golang静态内容嵌入器
08-14
embed: 另一个Golang静态内容嵌入器
HTML embed标签使用方法和属性详解
01-21
一、基本语法
复制代码代码如下:embed src=url说明:embed可以用来插入各种多媒体,格式可以是 Midi、Wav、AIFF、AU、MP3等等,Netscape及新版的IE 都支持。url为音频或视频文件及其路径,可以是相对路径或绝对路径。
示例:
复制代码代码如下:<embed src=”your.mid”>
二、属性设置
1、自动播放:
语法:autostart=true、false说明:该属性规定音频或视频文件是否在下载完之后就自动播放。true:音乐文件在下载完之后自动播放;false:音乐文件在下载完之后不自动播放。示例:
复制代码代码如下:<embed src=”you
debme:从embed.FS内部获取embed.FS
04-16
da! 听说您喜欢embed.FS ...
特征
提供一种从嵌入式目录获取embed.FS的方法
一种方法: FS()
您可以一直调用FS() ,直到...
100% embed.FS兼容
100%的代码覆盖率
例子
package main
import (
"embed"
"github.com/leaanthony/debme"
"io/fs"
// Example Filesystem:
//
// fixtures/
// ├── test1
// | └── onefile.txt
// └── test2
// └── inner
// ├── deeper
// | └── three.txt
// ├── one.txt
// └── two.txt
//go:embed fix
Go Embed简明教程
AndrewYZWang的博客
09-26
1144
Go Embed简明教程
go语言程序都是编译成二进制可执行文件的,但是实际执行时除了需要可执行程序,还需要一些静态文件,比如html模板等,于是就有人想如果Go官方能内建支持就好了。2019末一个提案被提出 issue#35950,期望Go官方编译器支持嵌入静态文件。后来Russ Cox专门写了一个设计文档 Go command support for embedded static assets, 并最终实现了它。
需要注意的这个功能在go 1.16beta之后才支持
对于单个的文件,支持嵌入为
Go1.16 新特性:一文快速上手 Go embed
EDDYCJY的博客
02-02
3507
大家好,我是正在沉迷学习煎鱼的煎鱼。在以前,很多从其他语言转过来 Go 语言的同学会问到,或是踩到一个坑。就是以为 Go 语言所打包的二进制文件中会包含配置文件的联同编译和打包。结果往往...
Golang 1.16 新特性-embed 包及其使用
云满笔记
10-11
916
请记住, 在您希望在 Web 服务器中嵌入文件但不允许用户查看所有文件的列表的情况下, 包含 Mac OS 的。将文件内容嵌入到字符串或字节数组类型变量的时候, 只能嵌入 1 个文件, 不能嵌入多个文件, 并且文件名不支持正则模式, 否则运行代码会报错。嵌入的这个基本概念是通过在代码里添加一个特殊的注释实现的, Go 会根据这个注释知道要引入哪个或哪几个文件。指令, 可以在编译阶段将静态资源文件打包进编译好的程序中, 并提供访问这些文件的能力。指令, 可以在同一个变量中嵌入多个目录。
go:embed 的使用
DisMisPres的博客
10-09
3771
简介
go:embed 是 go 1.16版本添加的新特性,可以在 go 生成的应用程序中嵌入静态文件(文件,文件夹)。部署的时候,直接扔一个二进制文件即可,不用再包含一些静态文件,考虑文件相对位置,因为它们已经被打包到生成的应用程序中了。
导入 embed 的 go 源文件可以使用 //go:embed 指令在编译时从包目录或子目录中将读取的内容转换成 string, []byte, 或者 embed.FS 类型的变量。
基本用法
目录层级:
下面用到的 hello.txt 的内容:
hello wor
golang的go:embed的使用注意事项
风之飘渺
08-26
1132
golang的go:embed的使用注意事项,避坑指南。
tomcat-embed-el-9.0.16.jar
01-08
tomcat-embed-el-9.0.16.jar
tomcat-embed-jasper-9.0.16.jar
01-08
tomcat-embed-jasper-9.0.16.jar
HTML5 embed 标签使用方法介绍
12-14
embed> 标签定义嵌入的内容,比如插件。 实例 <embed src="helloworld.swf" />HTML 4.01 与 HTML 5 之间的差异 <embed> 标签是 HTML 5 中的新标签。 属性 new : HTML5 中的新属性。 属性 值 ...
HTML5 embed标签定义和用法详解
12-14
embed> 标签定义嵌入的内容,比如插件。 实例 <embed src="helloworld.swf" /> HTML 4.01 与 HTML 5 之间的差异 <embed> 标签是 HTML 5 中的新标签。 属性 new : HTML5 中的新属性。 属性 ...
html标签之Object和EMBED标签详解
01-19
定义和用法 定义一个嵌入的对象。请使用此元素向您的 XHTML 页面添加多媒体。... <object> 标签用于包含对象,比如图像、音频、视频、Java applets、ActiveX、PDF 以及 Flash。 object 的初衷是取代 img 和 ...
embed embed
04-25
tags embed 页面标签 tags embed 页面标签
embed使用,embed播放多媒体
07-10
embed 播放多媒体 embed详细介绍 embed入门
HTML-embed代码详解
01-04
HTML-embed代码详解word文档
go:embed打包前段静态文件夹到二进制,并访问静态资源
wangge20091126的专栏
10-31
208
go embed
tomcat-embed-jasper
最新发布
03-16
Tomcat-embed-jasper是一个嵌入式的JSP引擎,它可以让开发者在应用程序中使用JSP技术,而不需要安装和配置独立的Tomcat服务器。它是Tomcat的一个子项目,可以方便地与Spring Boot等框架集成使用。
“相关推荐”对你有帮助么?
非常没帮助
没帮助
一般
有帮助
非常有帮助
提交
会飞的胖达喵
CSDN认证博客专家
CSDN认证企业博客
码龄11年
暂无认证
444
原创
2万+
周排名
165万+
总排名
190万+
访问
等级
1万+
积分
217
粉丝
446
获赞
241
评论
1176
收藏
私信
关注
热门文章
CSS中box-sizing: border-box;的作用
67809
Android studio断点调试(全在这里)
62140
css 中“~”和“>”以及“ ””是什么意思
49453
App中如何实现消息推送
35540
linux解压覆盖命令
32095
分类专栏
php笔记
174篇
qt
7篇
golang
198篇
系统笔记
81篇
c++
25篇
网络编程
12篇
cmake
3篇
git
12篇
数据结构
3篇
cgo
1篇
pb
5篇
WebRTC
3篇
kratos
7篇
k8s
1篇
rabbitMQ
4篇
微服务
1篇
consul
1篇
rpc
5篇
gin
2篇
etcd
2篇
docker
21篇
胖达go系列
2篇
笔记
1篇
sql笔记
35篇
linux笔记
94篇
前端笔记
126篇
javascript
53篇
微信开发
4篇
mysql
27篇
android
31篇
laravel
40篇
安全
3篇
redis
8篇
nodejs
2篇
微擎
6篇
淘宝开放平台
Python
39篇
微信小程序
27篇
C#/ASP.NET
16篇
java
3篇
vue
36篇
最新评论
tpl_form_field_category_2level() - 二级分类选择器说明
programmer_ada:
Python 中的装饰器是什么?
Golang面试问题汇总
悄悄*CS:
哈哈这个面经我每次找工作都看
windows复制文件到 vmware centos虚拟机问题
逐星578:
你解决了吗 我也是拖拽不了
echarts柱状图x轴文字纵向显示
weixin_57589475:
太牛咯
Docker容器时间与宿主机同步
TamadeC:
君之佳作,吾看甚欢,今谢君不吝共享,让吾窥得其中之奥妙!
您愿意向朋友推荐“博客详情页”吗?
强烈不推荐
不推荐
一般般
推荐
强烈推荐
提交
最新文章
Redis有哪些数据结构图解
与,或,异或
C++ 什么时候调用析构函数
2023年7篇
2022年86篇
2021年187篇
2020年161篇
2019年96篇
2018年33篇
2017年137篇
2016年106篇
2015年14篇
2014年28篇
2013年136篇
目录
目录
分类专栏
php笔记
174篇
qt
7篇
golang
198篇
系统笔记
81篇
c++
25篇
网络编程
12篇
cmake
3篇
git
12篇
数据结构
3篇
cgo
1篇
pb
5篇
WebRTC
3篇
kratos
7篇
k8s
1篇
rabbitMQ
4篇
微服务
1篇
consul
1篇
rpc
5篇
gin
2篇
etcd
2篇
docker
21篇
胖达go系列
2篇
笔记
1篇
sql笔记
35篇
linux笔记
94篇
前端笔记
126篇
javascript
53篇
微信开发
4篇
mysql
27篇
android
31篇
laravel
40篇
安全
3篇
redis
8篇
nodejs
2篇
微擎
6篇
淘宝开放平台
Python
39篇
微信小程序
27篇
C#/ASP.NET
16篇
java
3篇
vue
36篇
目录
评论
被折叠的 条评论
为什么被折叠?
到【灌水乐园】发言
查看更多评论
添加红包
祝福语
请填写红包祝福语或标题
红包数量
红包个数最小为10个
红包总金额
红包金额最低5元
余额支付
当前余额3.43元
前往充值 >
需支付:10.00元
取消
确定
下一步
知道了
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝
规则
hope_wisdom 发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额
抵扣说明:
1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。 2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。
余额充值