Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to embed files into Go binaries

Tags:

go

binaries

I have some text file that I read from my Go program. I'd like to ship a single executable, without supplying that text file additionally. How do I embed it into compilation on Windows and Linux?

like image 884
Zvika Avatar asked Jul 22 '13 19:07

Zvika


People also ask

How do I embed a file in Golang?

Using the Golang embed directive In the example above, we are using the directive //go:embed from embed package, followed by the filename we want to embed. On the next line, we create a new variable where the content of the file will be placed. This variable can be of type string, []byte, or FS(FileSystem).

What are binaries in go?

Go Binaries is an open-source server allowing non-Go users to quickly install tools written in Golang, without installing the Go compiler or a package manager — all you need is curl .

How do I read a file in Golang?

The simplest way of reading a text or binary file in Go is to use the ReadFile() function from the os package. This function reads the entire content of the file into a byte slice, so you should be careful when trying to read a large file - in this case, you should read the file line by line or in chunks.


2 Answers

===== Edit Jan 2021 =====

Starting with Go 1.16, released in Feb 2021, you can use the go:embed directive:

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

===== Original answer ======

Since Go 1.4, you can use go generate if you need more flexibility.

If you have more than one text file or the text file may change you might not want to hardcode the text file but include it at compile time.

If you have the following files:

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

And want to have access to the contents of all .txt files in main.go, you can include a special comment containing a go generate command.

main.go

package main  import "fmt"  //go:generate go run scripts/includetxt.go  func main() {     fmt.Println(a)     fmt.Println(b) } 

The go generate command will run the script after go:generate. In this case it runs a go script which reads all text files and outputs them as string literals into a new file. I skipped the error handling for shorter code.

script/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")) } 

To compile all .txt files into your exectutable:

$ go generate $ go build -o main 

Now your directory structure will look like:

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

Where textfiles.go was generated by go generate and script/includetxt.go

textfiles.go

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

And running main gives

$ ./main hello world 

This will work fine as long as you're encoding UTF8 encoded files. If you want to encode other files you have the full power of the go language (or any other tool) to do so. I used this technique to hex encode png:s into a single executable. That requires a minor change to includetxt.go.

like image 147
Johan Wikström Avatar answered Sep 30 '22 18:09

Johan Wikström


Use go-bindata. From the README:

This tool converts any file into managable Go source code. Useful for embedding binary data into a go program. The file data is optionally gzip compressed before being converted to a raw byte slice.

like image 35
joshlf Avatar answered Sep 30 '22 16:09

joshlf