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

如何将文件嵌入到Go二进制文件中,go,binaries,Go,Binaries,我有一些从围棋程序中读取的文本文件。我希望只提供一个可执行文件,而不另外提供该文本文件。 如何将其嵌入Windows和Linux上的编译中?使用。自述文件: 此工具将任何文件转换为可管理的Go源代码。有益于 将二进制数据嵌入go程序。文件数据是可选的 gzip在转换为原始字节片之前已压缩 可以使用将文本定义为常量或变量。字符串文字是通过用反引号括住字符串来定义的。e、 g.`string` 例如: package main import "fmt" func main() { con

我有一些从围棋程序中读取的文本文件。我希望只提供一个可执行文件,而不另外提供该文本文件。 如何将其嵌入Windows和Linux上的编译中?

使用。自述文件:

此工具将任何文件转换为可管理的Go源代码。有益于 将二进制数据嵌入go程序。文件数据是可选的 gzip在转换为原始字节片之前已压缩

可以使用将文本定义为常量或变量。字符串文字是通过用反引号括住字符串来定义的。e、 g.`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)
}
====编辑2021年1月===== 从2021年2月发布的Go 1.16开始,您可以使用以下指令:

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))
====原始答案====== 自从Go1.4以来,如果您需要更大的灵活性,可以使用

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

如果您有以下文件:

main.go
scripts/includetxt.go
a.txt
b.txt
如果您想访问main.go中所有.txt文件的内容,可以包含一个包含go generate命令的特殊注释

梅因,加油 go generate命令将在
go:generate
之后运行脚本。在本例中,它运行一个go脚本,读取所有文本文件,并将它们作为字符串文本输出到新文件中。我跳过了较短代码的错误处理

脚本/includeText.go 要将所有.txt文件编译为可执行文件,请执行以下操作:

$ go generate
$ go build -o main
现在,您的目录结构将如下所示:

main.go
main
scripts/includetxt.go
textfiles.go
a.txt
b.txt
其中textfiles.go由go generate和script/includeText.go生成

textfiles.go 运行main提供

$ ./main
hello
world

只要您对UTF8编码的文件进行编码,这就可以正常工作。如果您想对其他文件进行编码,您可以使用go语言(或任何其他工具)进行编码。我使用这种技术将png:s转换为单个可执行文件。这需要对includeText.go进行一个小的更改。

我使用一个简单的函数在运行
go generate
时读取一个外部模板,并从中生成go代码。将生成一个以字符串形式返回模板的函数。然后可以使用
tpl,err:=template.New(“myname”).parse(mynameTemplate())

我确实把代码放到了github上。你可能想试试


非常简单,但对我来说效果很好。

基于@CoreyOgburn注释,创建了以下代码段:

//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

应该创建一个包含文件的二进制文件

在寻找相同的东西时(2014年11月19日),作者正在评估声称进行文件嵌入的3个其他流行软件包:

  • (还有新的官员和另一个改进的官员)
  • 并解释为什么他最终提出了自己的方案:

  • 因此,在简单地尝试了所有这些(按顺序)之后,我自然而然地选择了Matt的,因为它是唯一一款开箱即用的功能(单个可执行文件中的HTTPS服务),即:

  • 可以获取一些目录,并以与兼容的方式递归地将所有文件嵌入其中
  • 可以选择禁用,以便与本地文件系统一起用于本地开发,而无需更改客户端代码
  • 不会在后续运行中更改输出文件。当文件更改时,具有合理大小的差异
  • 能够通过
    //go:generate
    完成工作,而不是强制您手动编写额外的go代码
  • 这一点对我来说很重要,而剩下的包由于这样或那样的原因没有发挥出那么好的效果

    从esc的自述文件:

    esc将文件嵌入go程序,并为其提供http.FileSystem接口

    它将所有命名文件或文件递归地添加到指定路径的命名目录下。输出文件提供了一个http.FileSystem接口,对标准库之外的包没有依赖关系

    检查,使用起来很友好

    主程序包
    进口(
    “net/http”
    “github.com/gobuffalo/packr”
    )
    func main(){
    框:=packr.NewBox(“/模板”)
    Handle(“/”,http.FileServer(box))
    http.listendServe(“:3000”,无)
    }
    
    使用go1.16,您可以开始使用
    嵌入
    ,这是帮助您将静态非go文件嵌入二进制文件的标准软件包

    文档:
    例如:


    对于go<1.16,您可以使用packr。这是一个非常棒的工具,您可以在

    上查看更多关于此的信息,尽管如果您的“文件”包含
    %
    之类的字符,它就不起作用了。很好!我不知道这个函数存在。这比在源代码中转储字符串要干净得多。奇怪的是,为什么我们必须在注释中编写预处理器命令,然后单独运行
    go generate
    ?无法
    go-build
    在命令发出通知时注意运行命令
    //go:generate…
    comment?从2019-07-23起,此代码不适用于包含反勾号的文本文件。它们要么产生语法错误,要么允许代码注入,这两种情况都不需要。我是Go newpie,它通过运行主文件为我提供了未定义的a和b,includedtext.Go文件已成功生成。@Bunyk,我在a中找到了这一解释:最新的Go版本,1.4,包括一个新命令,使运行此类工具更容易。它被称为go generate,其工作原理是扫描go源代码中的特殊注释,这些注释识别要运行的常规命令。理解go生成不是go构建的一部分很重要。它不包含依赖性分析,必须在运行go build之前显式运行。它打算由Go包的作者使用,而不是它的客户机。这现在有点过时了。生成代码不通过g
    //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