web-dev-qa-db-fra.com

Comment intégrer des fichiers dans des binaires Golang?

J'ai un fichier texte que j'ai lu à partir de mon programme Go. Je voudrais expédier un seul exécutable, sans fournir ce fichier texte en plus. Comment l'intégrer dans la compilation sur Windows et Linux?

42
Zvika

Utilisez go-bindata . Du README:

Cet outil convertit n'importe quel fichier en code source Go gérable. Utile pour incorporer des données binaires dans un programme go. Les données du fichier sont éventuellement compressées au format gzip avant d'être converties en une tranche d'octets bruts.

28
joshlf

Depuis Go 1.4, vous pouvez utiliser allez générer si vous avez besoin de plus de flexibilité.

Si vous avez plusieurs fichiers texte ou si le fichier texte peut changer, vous ne voudrez peut-être pas coder en dur le fichier texte mais l'inclure au moment de la compilation.

Si vous disposez des fichiers suivants:

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

Et si vous souhaitez avoir accès au contenu de tous les fichiers .txt dans main.go, vous pouvez inclure un commentaire spécial contenant une commande go generate.

main.go

package main

import "fmt"

//go:generate go run scripts/includetxt.go

func main() {
    fmt.Println(a)
    fmt.Println(b)
}

La commande go generate exécutera le script après go:generate. Dans ce cas, il exécute un script go qui lit tous les fichiers texte et les renvoie sous forme de littéraux de chaîne dans un nouveau fichier. J'ai ignoré la gestion des erreurs pour un code plus court.

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

Pour compiler tous les fichiers .txt dans votre fichier exécutable:

$ go generate
$ go build -o main

Maintenant, votre structure de répertoire ressemblera à:

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

Où textfiles.go a été généré par go generate et script/includesetxt.go

textfiles.go

package main 

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

Et le fonctionnement principal donne

$ ./main
hello
world

Cela fonctionnera bien tant que vous encodez des fichiers encodés UTF8. Si vous souhaitez encoder d'autres fichiers, vous disposez de la pleine puissance de la langue go (ou de tout autre outil) pour le faire. J'ai utilisé cette technique pour encodage hexadécimal png: s en un seul exécutable. Cela nécessite une modification mineure pour inclureetet.go.

48
Johan Wikström

Vous pouvez utiliser un string literal pour définir le texte comme une constante ou une variable. Les littéraux de chaîne sont définis en entourant la chaîne de guillemets. par exemple. `chaîne`.

Par exemple:

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)
}
5
Intermernet

Cherchait la même chose et est tombé sur esc: Embedding Static Assets in Go (d'ici le 19 novembre 2014) où l'auteur, Matt Jibson , évalue 3 autres packages populaires qui prétendent faire l'incorporation de fichiers:

  1. rakyll/statik
  2. jteeuwen/go-bindata (et le nouveau fonctionnaire go-bindata/go-bindata et un autre amélioré kevinburke/go-bindata )
  3. GeertJohan/go.rice

et expliquer pourquoi il a finalement trouvé son propre package:

  1. mjibson/esc

Donc, après les avoir tous brièvement essayés (dans cet ordre), j'ai naturellement choisi Matt esc car c'était le seul qui fonctionnait hors de la boîte avec nécessaire pour moi fonctionnalité, à savoir:

  1. Peut prendre certains répertoires et y incorporer récursivement tous les fichiers d'une manière compatible avec http.FileSystem
  2. Peut éventuellement être désactivé pour une utilisation avec le système de fichiers local pour le développement local sans changer le code du client
  3. Ne changera pas le fichier de sortie lors des exécutions suivantes a des différences de taille raisonnable lorsque les fichiers sont modifiés
  4. Capable de faire le travail via //go:generate au lieu de vous forcer à écrire manuellement du code Go supplémentaire

Le point # 2 était important pour moi et le reste des paquets pour une raison ou une autre n'a pas bien fonctionné.

Du README de l'esc:

esc intègre des fichiers dans les programmes go et leur fournit des interfaces http.FileSystem.

Il ajoute tous les fichiers nommés ou les fichiers récursivement sous les répertoires nommés au chemin spécifié. Le fichier de sortie fournit une interface http.FileSystem avec aucune dépendance sur les packages en dehors de la bibliothèque standard.

4
Sevenate

J'ai utilisé une fonction simple pour lire un modèle externe dans un cycle go generate Et pour générer du code Go à partir de celui-ci. Une fonction renvoyant le modèle sous forme de chaîne sera générée. On peut ensuite analyser la chaîne de modèle retournée en utilisant tpl, err := template.New("myname").Parse(mynameTemplate())

J'ai mis ce code dans github. Vous voudrez peut-être essayer https://github.com/wlbr/templify

Très simple, mais fonctionne assez bien pour moi.

2
wlbr

Sur la base du commentaire @CoreyOgburn et de cette commentaire Github , l'extrait de code suivant a été créé:

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

et courir

go generate

et par la suite

go build

devrait créer un binaire qui contient les fichiers

2
030

check packr , son assez convivial à utiliser

package main

import (
  "net/http"

  "github.com/gobuffalo/packr"
)

func main() {
  box := packr.NewBox("./templates")

  http.Handle("/", http.FileServer(box))
  http.ListenAndServe(":3000", nil)
}
1
zuo