您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“golang embed是什么”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“golang embed是什么”吧!
embed是什么
embed是在Go 1.16中新加入的包。它通過(guò)//go:embed
指令,可以在編譯階段將靜態(tài)資源文件打包進(jìn)編譯好的程序中,并提供訪問(wèn)這些文件的能力。
為什么需要embed
在以前,很多從其他語(yǔ)言轉(zhuǎn)過(guò)來(lái)Go語(yǔ)言的小伙伴會(huì)問(wèn)到,或者踩到一個(gè)坑:就是以為Go語(yǔ)言所打包的二進(jìn)制文件中會(huì)包含配置文件的聯(lián)同編譯和打包。
結(jié)果往往一把二進(jìn)制文件挪來(lái)挪去,就無(wú)法把應(yīng)用程序運(yùn)行起來(lái)了,因?yàn)闊o(wú)法讀取到靜態(tài)文件的資源。
無(wú)法將靜態(tài)資源編譯打包二進(jìn)制文件的話(huà),通常會(huì)有兩種解決方法:
第一種是識(shí)別這類(lèi)靜態(tài)資源,是否需要跟著程序走。
第二種就是將其打包進(jìn)二進(jìn)制文件中。
第二種情況的話(huà),Go以前是不支持的,大家就會(huì)借助各種花式的開(kāi)源庫(kù),例如:go-bindata/go-bindata
來(lái)實(shí)現(xiàn)。
但是在Go1.16起,Go語(yǔ)言自身正式支持了該項(xiàng)特性。
它有以下優(yōu)點(diǎn)
能夠?qū)㈧o態(tài)資源打包到二進(jìn)制包中,部署過(guò)程更簡(jiǎn)單。傳統(tǒng)部署要么需要將靜態(tài)資源與已編譯程序打包在一起上傳,或者使用docker
和dockerfile
自動(dòng)化前者,這是很麻煩的。
確保程序的完整性。在運(yùn)行過(guò)程中損壞或丟失靜態(tài)資源通常會(huì)影響程序的正常運(yùn)行。
靜態(tài)資源訪問(wèn)沒(méi)有io操作,速度會(huì)非???/strong>。
通過(guò) 官方文檔 我們知道embed嵌入的三種方式:string、bytes 和 FS(File Systems)。其中string
和[]byte
類(lèi)型都只能匹配一個(gè)文件,如果要匹配多個(gè)文件或者一個(gè)目錄,就要使用embed.FS
類(lèi)型。
特別注意:embed這個(gè)包一定要導(dǎo)入,如果導(dǎo)入不使用的話(huà),使用 _ 導(dǎo)入即可
比如當(dāng)前文件下有個(gè)hello.txt的文件,文件內(nèi)容為hello,world!
。通過(guò)go:embed
指令,在編譯后下面程序中的s變量的值就變?yōu)榱?code>hello,world!。
package mainimport ( _ "embed" "fmt")//go:embed hello.txtvar s stringfunc main() { fmt.Println(s)}
你還可以把單個(gè)文件的內(nèi)容嵌入為slice of byte,也就是一個(gè)字節(jié)數(shù)組。
package mainimport ( _ "embed" "fmt")//go:embed hello.txtvar b []bytefunc main() { fmt.Println(b)}
甚至你可以嵌入為一個(gè)文件系統(tǒng),這在嵌入多個(gè)文件的時(shí)候非常有用。
比如嵌入一個(gè)文件:
package mainimport ( "embed" "fmt")//go:embed hello.txtvar f embed.FSfunc main() { data, _ := f.ReadFile("hello.txt") fmt.Println(string(data))}
嵌入本地的另外一個(gè)文件hello2.txt, 支持同一個(gè)變量上多個(gè)go:embed
指令(嵌入為string或者byte slice是不能有多個(gè)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))}
當(dāng)前重復(fù)的go:embed
指令嵌入為embed.FS是支持的,相當(dāng)于一個(gè):
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))}
Go1.16 為了對(duì) embed
的支持也添加了一個(gè)新包 io/fs
。兩者結(jié)合起來(lái)可以像之前操作普通文件一樣。
嵌入的內(nèi)容是只讀的。也就是在編譯期嵌入文件的內(nèi)容是什么,那么在運(yùn)行時(shí)的內(nèi)容也就是什么。
FS文件系統(tǒng)值提供了打開(kāi)和讀取的方法,并沒(méi)有write的方法,也就是說(shuō)FS實(shí)例是線(xiàn)程安全的,多個(gè)goroutine可以并發(fā)使用。
embed.FS結(jié)構(gòu)主要有3個(gè)對(duì)外方法,如下:
// Open 打開(kāi)要讀取的文件,并返回文件的fs.File結(jié)構(gòu).func (f FS) Open(name string) (fs.File, error)// ReadDir 讀取并返回整個(gè)命名目錄func (f FS) ReadDir(name string) ([]fs.DirEntry, error)// ReadFile 讀取并返回name文件的內(nèi)容.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))}
當(dāng)然你也可以像前面的例子一樣寫(xiě)成多行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系統(tǒng)也采用這個(gè)模式。
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))}
在我們的項(xiàng)目中,是將應(yīng)用的常用的一些配置寫(xiě)在了.env的一個(gè)文件上,所以我們?cè)谶@里就可以使用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)}
到此,相信大家對(duì)“golang embed是什么”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢(xún),關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。