<<<<<<<<<<<<<<<< 2018/08/23 追記 <<<<<<<<<<<<<<<<
go-bindataは今はメンテされていないようです
代わりに私は今rakyll/statikを使うようにしています
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
例えば下記のようなディレクトリ構成のGoプロジェクトがあったとする。
. ├── files │ └── sample.txt └── main.go
sampleの中身は
sample! sample!! sample!!!
main.goの中身は
package main import ( "bufio" "fmt" "os" ) func main() { f, err := os.Open("files/sample.txt") if err != nil { panic(err) } scanner := bufio.NewScanner(f) for scanner.Scan() { fmt.Println(scanner.Text()) } f.Close() }
実行するとfiles/sample.txt
の中身がコンソールに出力される。単純なもの。
$ go run main.go sample! sample!! sample!!!
例えばこれをbuildしてGithubのReleaseとかで配布することを考える。
$ go build -o /tmp/print_file main.go
/tmp/print_fileでビルドされた成果物が置かれるので、これを実行する。
$ /tmp/print_file panic: open files/sample.txt: no such file or directory
go build
では指定されたパッケージの依存関係を解決していきながらビルドしていくのでGoで書かれていれば含まれるのですが、今回のファイルのようなリソースは含まれないため起きたようです。
flagパッケージを使ってコマンドラインからフィアルパスを渡してあげるとかにすると思うのですが、GithubのReleasesとかでバイナリファイルして置くだけで実行したい時ってあると思うんですよ!
go-bindata
go-bindataは指定されたリソースをバイト列でGoのソースコードに記載してそのデータにアクセスできるメソッドをつけてくれます。
例えば今回はfiles配下のファイルを対象としたいので下記のようにコマンドを実行します。
$ go-bindata files
このコマンドを実行することでbindata.go
が生成されます。
. ├── bindata.go ├── files │ └── sample.txt └── main.go
今生成したデータに対してアクセスするにはREADME.mdにも記載されていますがAsset
を使用します。
今回のファイルの中身を出力するものを書き換えると
package main import ( "fmt" ) func main() { b, err := Asset("files/sample.txt") if err != nil { panic(err) } s := string(b) fmt.Print(s) }
Assetでは[]byte
で返ってきます。
先程と同じようにビルドします。今回は先程go-bindata
で作成したbindata.go
も一緒にビルドに含めます。
$ go build -o /tmp/print_file main.go bindata.go $ /tmp/print_file sample! sample!! sample!!!
おー
最後に
今回はGoのビルドを行う際にGoファイル以外のリソースを含める方法を書いた。
大きすぎるファイルはビルドにも時間がかかるし配布も大変だろうけど小さい設定ファイル的なものだったらgo-bindataを使用して一緒にビルドしてしまうという手も良さそう。
使っていきたい