golang官方嵌入文件到可執行程序


前言

在go官方出嵌入文件的方法前我在網上找過,並且自己還研究過,雖然沒有問題,但是既然官方支持還是用起來吧。
看了下go源碼embed/embed.go很簡單,並且看embed/internal/embedtest/embed_test.go就知道如何使用。

示例程序

嵌入文件直接訪問

原理是使用go:embed標簽來完成。下面是直接讀取文件內容,需要注意下面幾點。
文件不是utf8編碼時,輸出內容為中文會亂碼。
測試過嵌入文件只能為源碼文件同級目錄和子目錄下的文件,試過其他目錄的絕對路徑或相對路徑會報錯。
如果路徑包含空格可以使用雙引號或反引號括起來。
變量的類型只能是string、[]byte、embed.FS,即使是這三個類型的別名也不行。
我測試過幾個能想到的場景,有些會報錯,所以在使用時需要注意。

package main

import (
    _ "embed"
)

//go:embed test.txt
var testString string  // 當前目錄,解析為string類型

//go:embed test.txt
var testByte []byte  // 當前目錄,解析為[]byte類型

//go:embed test/test.txt
var testAbsolutePath string  // 子目錄,解析為string類型

//go:embed notExistsFile
var testErr0 string // 文件不存在,編譯報錯:pattern notExistsFile: no matching files found

//go:embed dir
var testErr1 string // dir是目錄,編譯報錯:pattern dir: cannot embed directory dir: contains no embeddable files

//go:embed ../test.txt
var testErr2 string // 相對路徑,不是當前目錄或子目錄,編譯報錯:pattern ../test.txt: invalid pattern syntax

//go:embed D:\test.txt
var testErr3 string // 絕對路徑,編譯報錯:pattern D:\test.txt: no matching files found

func main() {
    println(testString)
    println(string(testByte))
    println(testAbsolutePath)
}

嵌入文件列表

package main

import (
    "embed"
    "io"
    "os"
)

//go:embed test0.txt test1.txt test1*.txt
//go:embed test/test0.txt test/test1.txt
//go:embed test0
var fileList embed.FS
/*
使用上述方法可以將多個文件或目錄添加到fileList中。
1. 添加多個文件,且支持"*"號通配文件。
2. 支持子目錄文件。
3. 支持嵌入一個目錄。
*/

func main() {
    testDir, err := fileList.ReadDir("test0")
    if err != nil {
        panic(err)
    }
    for _, v := range testDir {
        println(v.Name()) // 打印嵌入的目錄內容
    }

    // 使用fileList.Open可以生成一個對象,可以通過文件流那樣讀出來
    testFile, err := fileList.Open("test0.txt")
    if err != nil {
        panic(err)
    }
    io.Copy(os.Stdout, testFile)

    testFile, err = fileList.Open("test112.txt")
    if err != nil {
        panic(err)
    }
    io.Copy(os.Stdout, testFile)

    testFile, err = fileList.Open("test/test1.txt")
    if err != nil {
        panic(err)
    }
    io.Copy(os.Stdout, testFile)

    // 直接將文件內容讀出來
    data, err := fileList.ReadFile("test111.txt")
    if err != nil {
        panic(err)
    }
    println(string(data))
}

嵌入http服務器

以前都需要將http服務器和文件都部署,現在可以直接使用,而且也超級方便。

package main

import (
    "embed"
    "net/http"
)

//go:embed test0.txt test1.txt test1*.txt
//go:embed test/test0.txt test/test1.txt
//go:embed test0
var fileList embed.FS

func main() {
    http.Handle("/", http.FileServer(http.FS(fileList)))
    http.ListenAndServe(":8080", nil)
}

下面是web訪問結果:

總結

今天看到go1.16發布,看了下特性,支持嵌入文件到可執行程序中,所以研究了一下。
我發現直接看源碼的_test測試文件就知道是如何使用的,都不需要到處搜教程。
所以說學習要知其然且知其所以然,不然天天搜別人的示例代碼,卻不知道原理,是不能靈活使用的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM