У меня есть текстовый файл, который я прочитал из моей программы Go. Я хотел бы отправить один исполняемый файл, не предоставляя этот текстовый файл дополнительно. Как мне включить его в компиляцию на Windows и Linux?
Как встроить файлы в двоичные файлы Golang?
Ответ 1
Используйте go-bindata. От README:
Этот инструмент преобразует любой файл в управляемый исходный код Go. Полезно для встраивание двоичных данных в программу go. Данные файла необязательно GZIP сжимается перед преобразованием в необработанный фрагмент байта.
Ответ 2
Так как Go 1.4, вы можете использовать go генерировать, если вам нужна большая гибкость.
Если у вас есть несколько текстовых файлов или текстовый файл может измениться, вам может не потребоваться жестко указать текстовый файл, а включить его во время компиляции.
Если у вас есть следующие файлы:
main.go
scripts/includetxt.go
a.txt
b.txt
И хочу иметь доступ к содержимому всех файлов .txt в main.go, вы можете включить специальный комментарий, содержащий команду 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 запускает script после go:generate
. В этом случае он запускает go script, который считывает все текстовые файлы и выводит их как строковые литералы в новый файл. Я пропустил обработку ошибок для более короткого кода.
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"))
}
Чтобы скомпилировать все .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
textfiles.go
package main
const (
a = `hello`
b = `world`
)
И работает main дает
$ ./main
hello
world
Это будет работать нормально, если вы кодируете кодированные файлы UTF8. Если вы хотите кодировать другие файлы, у вас есть полная сила языка go (или любого другого инструмента) для этого. Я использовал эту технику для hex encode png: s в один исполняемый файл. Это требует незначительных изменений для includeetxt.go.
Ответ 3
Вы можете использовать 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)
}
Ответ 4
Искал то же самое и наткнулся на esc: встраивание статических ресурсов в Go (до 19 ноября 2014 года), где автор, Мэтт Джибсон, оценивает 3 других популярных пакета, которые, как утверждают, делают вложение файла:
- rakyll/Statik
- jteeuwen/go-bindata (и новый официальный go-bindata/go-bindata и еще один улучшенный вариант kevinburke/go-bindata)
- GeertJohan/go.rice
и объясните, почему он в итоге придумал свой пакет:
Итак, после краткого опробования их всех (в таком порядке) я, естественно, остановился на Мэтте esc, так как он был единственным, который работал из коробки с необходимой мне функциональностью, а именно:
- Может взять несколько каталогов и рекурсивно внедрить все файлы в них способом, совместимым с http.FileSystem
- .При желании можно отключить для использования с локальной файловой системой для локальной разработки без изменения кода клиента
- Не изменит выходной файл при последующих запусках, имеет различия в размерах при изменении файлов
- Способен выполнять работу через
//go:generate
вместо того, чтобы заставлять вас вручную вводить дополнительный код Go
Вопрос # 2 был важен для меня, а остальные пакеты по тем или иным причинам не сработали.
От esc README:
esc встраивает файлы в программы go и предоставляет им интерфейсы http.FileSystem.
Он добавляет все именованные файлы или файлы рекурсивно в именованные каталоги по указанному пути. Выходной файл предоставляет интерфейс http.FileSystem с нулевыми зависимостями от пакетов вне стандартной библиотеки.
Ответ 5
Я использовал простую функцию для чтения внешнего шаблона в прогоне go generate
и для генерации кода Go из него. Будет создана функция, возвращающая шаблон в виде строки. Затем можно проанализировать возвращаемую строку шаблона с помощью tpl, err := template.New("myname").Parse(mynameTemplate())
Я поставил этот код в github. Возможно, вы захотите попробовать https://github.com/wlbr/templify
Очень просто, но работает для меня довольно хорошо.
Ответ 6
На основе комментария @CoreyOgburn и этого комментария Github был создан следующий фрагмент:
//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
проверьте упаковщик, его довольно удобно использовать
package main
import (
"net/http"
"github.com/gobuffalo/packr"
)
func main() {
box := packr.NewBox("./templates")
http.Handle("/", http.FileServer(box))
http.ListenAndServe(":3000", nil)
}