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?
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).
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 .
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.
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))
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.
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.
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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With