Ich verwende io/ioutil
, um eine kleine Textdatei zu lesen:
fileBytes, err := ioutil.ReadFile("/absolute/path/to/file.txt")
Und das funktioniert gut, aber das ist nicht gerade tragbar. In meinem Fall befinden sich die Dateien, die ich öffnen möchte, in meinem GOPATH, zum Beispiel:
/Users/matt/Dev/go/src/github.com/mholt/mypackage/data/file.txt
Da der data
Ordner direkt neben dem Quellcode angezeigt wird, möchte ich nur den relativen Pfad angeben:
data/file.txt
Aber dann bekomme ich diesen Fehler:
Panik: Öffnen Sie data / file.txt: Keine solche Datei oder kein solches Verzeichnis
Wie kann ich Dateien über ihren relativen Pfad öffnen, insbesondere wenn sie neben meinem Go-Code gespeichert sind?
( Beachten Sie, dass es bei meiner Frage speziell um das Öffnen von Dateien relativ zum GOPATH geht. Das Öffnen von Dateien mit einem beliebigen relativen Pfad in Go ist so einfach wie das Angeben des relativen Pfads anstelle eines absoluten Pfads. Dateien werden relativ zum Arbeitsverzeichnis der kompilierten Binärdatei geöffnet In diesem Fall möchte ich Dateien öffnen, die sich darauf beziehen, wo die Binärdatei kompiliert wurde. Im Nachhinein ist dies eine schlechte Entwurfsentscheidung.)
Antworten:
Hmm ... das
path/filepath
Paket hatAbs()
das, was ich (bisher) brauche, obwohl es etwas unpraktisch ist:absPath, _ := filepath.Abs("../mypackage/data/file.txt")
Dann
absPath
lade ich die Datei und sie funktioniert einwandfrei.Beachten Sie, dass sich die Datendateien in meinem Fall in einem Paket befinden, das von dem
main
Paket getrennt ist, von dem aus ich das Programm ausführe. Wenn alles im selben Paket wäre, würde ich das führende entfernen../mypackage/
. Da dieser Pfad offensichtlich relativ ist, haben verschiedene Programme unterschiedliche Strukturen und müssen entsprechend angepasst werden.Wenn es eine bessere Möglichkeit gibt, externe Ressourcen mit einem Go-Programm zu nutzen und portabel zu halten, können Sie eine weitere Antwort hinzufügen.
quelle
ioutil.ReadFile
müsste die relativen Pfade erweitern , um richtig zu arbeiten, aber es ist völlig unnötig. Das funktioniert gut :ioutil.ReadFile("../mypackage/data/file.txt")
. Es gibt wahrscheinlich viele andere Fälle, in denen Sie einen absoluten Pfad erstellen möchten, aber es scheint, dass die Verwendung mitio.ReadFile
nicht einer von ihnen ist.das scheint ziemlich gut zu funktionieren:
import "os" import "io/ioutil" pwd, _ := os.Getwd() txt, _ := ioutil.ReadFile(pwd+"/path/to/file.txt")
quelle
import "path/filepath"
und Anrufenfilepath.Join(...)
(mit KapitalJ
). :-)os.Open(pwd + "../mocks/product/default.json")
Wie gehen Sie mit diesem Fall um? es nimmt dies als wörtlich.Ich habe Gobundle geschrieben , um genau dieses Problem zu lösen. Es generiert Go-Quellcode aus Datendateien, die Sie dann in Ihre Binärdatei kompilieren. Sie können dann über eine VFS-ähnliche Ebene auf die Dateidaten zugreifen. Es ist vollständig portabel und unterstützt das Hinzufügen ganzer Dateibäume, die Komprimierung usw.
Der Nachteil ist, dass Sie einen Zwischenschritt benötigen, um die Go-Dateien aus den Quelldaten zu erstellen. Normalerweise benutze ich dafür make.
So würden Sie alle Dateien in einem Bundle durchlaufen und die Bytes lesen:
for _, name := range bundle.Files() { r, _ := bundle.Open(name) b, _ := ioutil.ReadAll(r) fmt.Printf("file %s has length %d\n", name, len(b)) }
Sie können ein echtes Beispiel für die Verwendung in meinem GeoIP- Paket sehen. Der
Makefile
generiert den Code undgeoip.go
verwendet das VFS.quelle
Ich denke, Alec Thomas hat die Antwort geliefert, aber meiner Erfahrung nach ist sie nicht narrensicher. Ein Problem beim Kompilieren von Ressourcen in die Binärdatei besteht darin, dass das Kompilieren abhängig von der Größe Ihrer Assets möglicherweise viel Speicher benötigt. Wenn sie klein sind, gibt es wahrscheinlich keinen Grund zur Sorge. In meinem speziellen Szenario verursachte eine 1-MB-Schriftartdatei beim Kompilieren etwa 1 GB Arbeitsspeicher. Es war ein Problem, weil ich wollte, dass es auf einem Raspberry Pi verfügbar ist. Dies war mit Go 1.0; Möglicherweise haben sich die Dinge in Go 1.1 verbessert.
In diesem speziellen Fall verwende ich einfach das
go/build
Paket, um das Quellverzeichnis des Programms basierend auf dem Importpfad zu finden. Dies setzt natürlich voraus, dass Ihre ZieleGOPATH
eingerichtet sind und die Quelle verfügbar ist. Es ist also nicht in allen Fällen eine ideale Lösung.quelle