小编典典

如何将文件嵌入到 Go 二进制文件中

go

我有一些从 Go 程序中读取的文本文件。我想发布一个可执行文件,而不额外提供该文本文件。如何将其嵌入到 Windows 和 Linux 上的编译中?


阅读 188

收藏
2021-12-28

共2个答案

小编典典

使用go-bindata。从自述文件:

该工具将任何文件转换为可管理的 Go 源代码。用于将二进制数据嵌入到 go 程序中。文件数据在被转换为原始字节切片之前可选地进行 gzip 压缩。

2021-12-28
小编典典

从 2021 年 2 月发布的 Go 1.16 开始,您可以使用以下go:embed指令:

import "embed"

//go:embed hello.txt
var s string
print(s)

//go:embed hello.txt
var b []byte
print(string(b))

//go:embed hello.txt
var f embed.FS
data, _ := f.ReadFile("hello.txt")
print(string(data))

======原始答案======

从 Go 1.4 开始,如果需要更多灵活性,可以使用go generate

如果您有多个文本文件或文本文件可能会更改,您可能不想对文本文件进行硬编码,而是在编译时将其包含在内。

如果您有以下文件:

main.go
scripts/includetxt.go
a.txt
b.txt

并且想要访问 main.go 中所有 .txt 文件的内容,您可以包含一个包含 go generate 命令的特殊注释。

main.go

package main

import "fmt"

//go:generate go run scripts/includetxt.go

func main() {
    fmt.Println(a)
    fmt.Println(b)
}

go generate 命令将在go:generate. 在这种情况下,它运行一个 go 脚本,该脚本读取所有文本文件并将它们作为字符串文字输出到一个新文件中。我跳过了较短代码的错误处理。

脚本/includetxt.go

package main

import (
    "io"
    "io/ioutil"
    "os"
    "strings"
)

// Reads all .txt files in the current folder
// and encodes them as strings literals in textfiles.go
func main() {
    fs, _ := ioutil.ReadDir(".")
    out, _ := os.Create("textfiles.go")
    out.Write([]byte("package main \n\nconst (\n"))
    for _, f := range fs {
        if strings.HasSuffix(f.Name(), ".txt") {
            out.Write([]byte(strings.TrimSuffix(f.Name(), ".txt") + " = `"))
            f, _ := os.Open(f.Name())
            io.Copy(out, f)
            out.Write([]byte("`\n"))
        }
    }
    out.Write([]byte(")\n"))
}

将所有 .txt 文件编译到您的可执行文件中:

$ go generate
$ go build -o main

现在您的目录结构将如下所示:

main.go
main
scripts/includetxt.go
textfiles.go
a.txt
b.txt

textfiles.go 是由 go generate 和 script/includetxt.go 生成的

文本文件.go

package main 

const (
a = `hello`
b = `world`
)

并运行 main 给出

$ ./main
hello
world

只要您对 UTF8 编码的文件进行编码,这就会正常工作。如果你想编码其他文件,你可以使用 go 语言(或任何其他工具)的全部功能来这样做。我使用这种技术将png:s十六进制编码为单个可执行文件。这需要对 includetxt.go 稍作改动。

2021-12-28