2013-06-12 32 views
26
私は小さなテキストファイル読み取りに io/ioutilを使用してい

Goで相対パスを使用してファイルを開くにはどうすればよいですか?

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 

しかし、その後、私はこのエラーを取得する:

panic: open data/file.txt: no such file or directory

どのように私は彼らが私の移動コードと一緒に住んでいる場合は特に、彼らの相対パスを使用してファイルを開くことができますか?

+5

GOPATHは、あなたのプログラムがコンパイルされるとない大きな意味を持っている、とさえ少ないあなたがそれを配布する場合。 –

+0

あなたが望むように思えるのは、コンパイルされたプログラムにファイルを埋め込むのに似ています。 –

+2

データファイルをソースとは別にしたいのですが。データファイルは、プログラムの機能にとって不可欠です。だから誰かが私のソースコードを(データファイルを横にして)プルダウンしてコンパイルして実行すると、データファイルはソースコードの近くまたはプログラムが実行されている場所の近くに存在するため、相対パスを使用してロードされます。 – Matt

答えて

40

うーん... path/filepathパッケージには、それは少し不便だけれども、私は(今のところ)必要なものを行いAbs()あります

absPath, _ := filepath.Abs("../mypackage/data/file.txt") 

その後、私は、ファイルをロードするためにabsPathを使用して、それが正常に動作します。

私の場合、データファイルは、私がプログラムを実行しているmainパッケージとは別のパッケージに入っています。もしそれがすべて同じパッケージに入っていたら、先導../mypackage/を取り除くでしょう。この経路は明らかに相対的なものなので、異なるプログラムは異なる構造を持ち、それに応じて調整する必要があります。

Goプログラムで外部リソースを使用して移植性を保つための良い方法がある場合は、別の答えを投稿しても構いません。

+0

Ha、ほぼ私は今から相対パスでファイルを開くのに問題はなかったし、この小さなトリックを使わなければならなかった。私はそれが私が何かを学んだことを意味すると思います。 – Matt

+8

あなたは何を学びましたか? :)このようなファイルをパッケージ間で共有しないのはどうでしょうか? – srt32

+3

@Matt、愛を分かち合う。あなたが私たちのために何か良いものを持っているなら、この「小さなトリック」を使いたくないのです。あなたはgoogleで一番の結果です。 – OGHaza

6

私はこの問題を正確に解決するために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を使用します。

+0

@ BurntSushi5は良い点があります。私のデータファイルのサイズは数百MBです。これはクールですが、私はバイナリにプレーンテキストファイルをコンパイルすることは実現可能な選択肢ではないと思います。 – Matt

1

私はAlec ThomasがThe Answerを提供してくれたと思っていますが、私の経験上、それは間違いありません。私がバイナリにリソースをコンパイルする際に抱えた1つの問題は、コンパイルにはアセットのサイズに応じて多くのメモリが必要になることです。彼らが小さいなら、おそらく何も心配する必要はありません。私の特定のシナリオでは、1MBのフォントファイルが、コンパイルに約1GBのメモリを必要とするコンパイルを引き起こしていました。それはラズベリーパイでゲットできるようにしたいので、問題でした。これはGo 1.0で行われました。 Go 1.1で改善された可能性があります。

そのようなケースでは、go/buildパッケージを使用して、インポートパスに基づいてプログラムのsource directoryを探します。もちろん、ターゲットにGOPATHが設定されていて、ソースが利用可能であることが必要です。したがって、すべてのケースで理想的なソリューションではありません。

12

これはかなりうまく動作するようです:

import "os" 
import "io/ioutil" 

pwd, _ := os.Getwd() 
txt, _ := ioutil.ReadFile(pwd+"/path/to/file.txt") 
関連する問題