io/ioutil
を使用して小さなテキストファイルを読み取ります。
fileBytes, err := ioutil.ReadFile("/absolute/path/to/file.txt")
そして、それは問題なく動作しますが、これは厳密には移植性がありません。私の場合、開きたいファイルはGOPATHにあります。例えば:
/Users/matt/Dev/go/src/github.com/mholt/mypackage/data/file.txt
data
フォルダーはソースコードのすぐ横にあるので、相対パスを指定するだけです。
data/file.txt
しかし、私はこのエラーを受け取ります:
パニック:open data/file.txt:そのようなファイルまたはディレクトリはありません
特にGoコードと一緒に存在する場合、相対パスを使用してファイルを開くにはどうすればよいですか?
(GOPATHに関連するファイルを開くことに関する質問です。 Goで相対パスを使用してファイルを開くことは、絶対パスではなく相対パスを指定するのと同じくらい簡単です;ファイルは、コンパイルされたバイナリの作業ディレクトリに関連して開かれます。私の場合、バイナリがコンパイルされた場所に関連してファイルを開きたいと思います。後知恵では、これは悪い設計決定です。)
うーん... _path/filepath
_パッケージには Abs()
があり、これは(今のところ)必要なことをしますが、少し不便です:
_absPath, _ := filepath.Abs("../mypackage/data/file.txt")
_
次に、absPath
を使用してファイルをロードすると、正常に機能します。
私の場合、データファイルは、プログラムを実行しているmain
パッケージとは別のパッケージにあることに注意してください。すべてが同じパッケージに含まれている場合は、先頭の_../mypackage/
_を削除します。このパスは明らかに相対的であるため、異なるプログラムは異なる構造を持ち、それに応じて調整する必要があります。
Goプログラムで外部リソースを使用して移植性を維持するより良い方法がある場合は、お気軽に別の回答を投稿してください。
これはかなりうまくいくようです:
import "os"
import "io/ioutil"
pwd, _ := os.Getwd()
txt, _ := ioutil.ReadFile(pwd+"/path/to/file.txt")
この問題を正確に解決するために gobundle と書きました。データファイルからGoソースコードを生成し、それをバイナリにコンパイルします。その後、VFSのようなレイヤーを介してファイルデータにアクセスできます。完全に移植可能で、ファイルツリー全体の追加、圧縮などをサポートします。
欠点は、ソースデータからGoファイルを構築するための中間ステップが必要なことです。私は通常、これにmakeを使用します。
バンドル内のすべてのファイルを反復してバイトを読み取る方法は次のとおりです。
for _, name := range bundle.Files() {
r, _ := bundle.Open(name)
b, _ := ioutil.ReadAll(r)
fmt.Printf("file %s has length %d\n", name, len(b))
}
GeoIP パッケージで実際の使用例を見ることができます。 Makefile
はコードを生成し、 geoip.go
はVFSを使用します。
アレック・トーマスが答えを提供したと思いますが、私の経験ではそれは絶対確実ではありません。リソースをバイナリにコンパイルする際に抱えていた問題の1つは、資産のサイズによってはコンパイルに大量のメモリが必要になる場合があることです。小さい場合は、おそらく心配する必要はありません。私の特定のシナリオでは、1MBのフォントファイルにより、コンパイルに約1GBのメモリが必要になりました。 Raspberry Piで入手できるようにしたかったので、問題でした。これはGo 1.0でのものでした。 Go 1.1では状況が改善された可能性があります。
そのため、特定のケースでは、go/build
パッケージを使用して、インポートパスに基づいてプログラムの ソースディレクトリ を見つけることを選択します。もちろん、これにはターゲットにGOPATH
が設定されていて、ソースが利用可能であることが必要です。したがって、すべての場合に理想的なソリューションではありません。