我有一些我从Go程序中读取的文本文件。我想发送一个可执行文件,而不另外提供该文本文件。 如何将其嵌入到Windows和Linux的编译中?
答案 0 :(得分:43)
从Go 1.4开始,如果您需要更多灵活性,可以使用go generate。
如果您有多个文本文件或文本文件可能更改,您可能不想对文本文件进行硬编码,但在编译时将其包含在内。
如果您有以下文件:
main.go
scripts/includetxt.go
a.txt
b.txt
想要访问main.go中所有.txt文件的内容,您可以添加一个包含go generate命令的特殊注释。
package main
import "fmt"
//go:generate go run scripts/includetxt.go
func main() {
fmt.Println(a)
fmt.Println(b)
}
go generate命令将在go:generate
之后运行脚本。在这种情况下,它运行一个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文件编译到exectutable:
$ 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
生成package main
const (
a = `hello`
b = `world`
)
运行main给出了
$ ./main
hello
world
只要您编码UTF8编码文件,这将正常工作。如果要对其他文件进行编码,则可以使用go语言(或任何其他工具)的全部功能。我使用这种技术将hex encode png:s转换为单个可执行文件。这需要对includetxt.go进行微小的更改。
答案 1 :(得分:28)
使用go-bindata。来自自述文件:
此工具将任何文件转换为可管理的Go源代码。对...有用 将二进制数据嵌入到go程序中。文件数据是可选的 gzip在转换为原始字节切片之前被压缩。
答案 2 :(得分:5)
您可以使用string literal
将文本定义为常量或变量。字符串文字是通过用反引号括起字符串来定义的。例如`string`。
例如:
package main
import "fmt"
func main() {
const text = `
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit
amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante
hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet
vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut
libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet,
consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a
semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis.
Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut
convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis
quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis
parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae
nisi at sem facilisis semper ac in est.
`
fmt.Println(text)
}
答案 3 :(得分:3)
在寻找相同的东西时,遇到esc: Embedding Static Assets in Go(到2014年11月19日),作者Matt Jibson正在评估另外3个声称可以嵌入文件的流行软件包:
并解释为什么他最终想出自己的包裹:
因此,在短暂地尝试了所有顺序之后,我自然选择了马特(Matt)的esc,因为它是唯一对我有帮助的现成产品 功能,即:
//go:generate
完成工作,而不必强迫您手动编写其他Go代码#2 这点对我来说很重要,而其他软件包出于某种原因却无法很好地解决问题。
从esc的自述文件:
esc将文件嵌入到go程序中,并为它们提供http.FileSystem接口。
它将所有指定的文件或文件递归添加到指定路径下的指定目录下。输出文件提供了一个http.FileSystem接口,该接口对标准库之外的包的依赖性为零。
答案 4 :(得分:3)
使用 go1.16,您可以开始使用 embed
,这是一个标准包,可帮助您将静态非 Go 文件嵌入到二进制文件中 >
文档:https://pkg.go.dev/embed
示例:https://blog.carlmjohnson.net/post/2021/how-to-use-go-embed/
对于 go < 1.16,您可以使用 packr。这是一个很棒的工具,您可以在 https://github.com/gobuffalo/packr
上查看更多信息答案 5 :(得分:2)
我使用一个简单的函数来读取go generate
运行中的外部模板,并从中生成Go代码。将生成将模板作为字符串返回的函数。然后,可以使用tpl, err := template.New("myname").Parse(mynameTemplate())
我确实把代码放到了github上。您可能想尝试https://github.com/wlbr/templify
很简单,但对我很有用。
答案 6 :(得分:2)
基于@CoreyOgburn注释和此Github comment,创建了以下代码段:
//go:generate statik -src=./html
package main
import (
_ "./statik"
"github.com/rakyll/statik/fs"
)
func statikFile() {
s, _ := fs.New() f, _ := s.Open("/tmpl/login.html") b, _ := ioutil.ReadAll(f) t, _ := template.New("login").Parse(string(b)) t.Execute(w, nil) }
然后运行
go generate
随后
go build
应创建一个包含文件的二进制文件
答案 7 :(得分:1)
检查packr,使用起来非常友好
package main
import (
"net/http"
"github.com/gobuffalo/packr"
)
func main() {
box := packr.NewBox("./templates")
http.Handle("/", http.FileServer(box))
http.ListenAndServe(":3000", nil)
}