次期 Go 言語で導入される(かもしれない) io/fs パッケージについて予習する
先日行われた “Go 1.15 Release Party in Japan” で紹介されていた File System Interfaces のドラフト案について予習がてら覚え書きとして記しておく。
たとえば /path/to/filename.txt
のようにツリー型のディレクトリ・ファイル構成のファイルシステムは多い。
メジャーな OS のファイルシステムは大抵そうだし Web のパスや書庫ファイル(*.tar
や *.zip
など)もツリー型のディレクトリ・ファイル構成になっている。
たとえば Go の標準パッケージ
などは(ほぼ)同じツリー型だが使い方やメソッド名などが微妙に異なっている。
またサードパーティ製のパッケージでは, rakyll/statik
のように,実行モジュールにディレクトリ・ファイルをまるっと埋め込めるものもあったりする1。
こういったパッケージに対して統一した interface 型を提供して互換性を高めようというわけだ。 したら,テストとかもやり易くなるしね(笑)
fs.FS 型と fs.File 型
ドラフト案では io/fs
パッケージを新たに作ってファイルシステムの汎化を定義するようだ。
まず,ファイルシステムの汎化型 fs.FS
は以下のように定義するらしい。
type FS interface {
Open(name string) (File, error)
}
また fs.FS.Open()
メソッドの返り値になっている fs.File
型は
type File interface {
Stat() (os.FileInfo, error)
Read([]byte) (int, error)
Close() error
}
と定義される。
たとえば,通常のファイルの読み書きについて
type myFS struct{}
func NewFS() fs.FS {
return &myFS{}
}
func (fsys *myFS) Open(name string) (fs.File, error) {
return os.Open(name)
}
みたいに定義すれば
func main() {
f, err := NewFS().Open("no-exist.txt")
if err != nil {
fmt.Println(err)
return
}
defer f.Close()
//Output:
//open no-exist.txt: no such file or directory
}
てな感じに書ける。 どやさ!
ちなみにディレクトリ区切り文字はスラッシュ “/
” で(実際のファイルシステムに関わらず)統一するらしい。
また相対パス指定で “.
” や “..
” は使えないようにするようだ。
まぁ,実際にはパス変換関数とか必要になるかもしれないね。
ファイルシステム・インタフェースの拡張
上述の説明だと「http
.FileSystem
型を使えばええんちゃうん?」となる。
実際 http
.FileSystem
型は
type File interface {
io.Closer
io.Reader
io.Seeker
Readdir(count int) ([]os.FileInfo, error)
Stat() (os.FileInfo, error)
}
type FileSystem interface {
Open(name string) (File, error)
}
と定義されているため fs.FS
/ fs.File
型とほぼ変わらない2。
駄菓子菓子。
io/fs
パッケージでは拡張機能を定義した型も用意するらしい。
たとえばファイル情報を取得する Stat()
メソッドを含む
type StatFS interface {
FS
Stat(name string) (os.FileInfo, error)
}
や,ディレクトリエントリを読む機能を含む
type ReadDirFS interface {
FS
ReadDir(name string) ([]os.FileInfo, error)
}
といった interface 型も用意されている。
他にもファイルの内容を一括で読み込める
type ReadFileFS interface {
FS
ReadFile(name string) ([]byte, error)
}
や Glob()
メソッドが使える
type GlobFS interface {
FS
Glob(pattern string) ([]string, error)
}
も用意するようだ。 実際にはこれらの interface 型を組み合わせて使うことになると思われる。
【2020-12-14 追記】
2021年2月リリース予定の Go 1.16 で実行モジュールへの任意のファイルの埋め込み機能が公式にサポートされるらしい。
- Big Sky :: Go に go:embed が入った。
- Go1.16で追加されるembedとio/fsパッケージについてざっと調べた - Qiita
- go:embed 詳解 - 使用編 - - Qiita
うまくすればこの記事の io/fs
パッケージとも将来的に統合されるかもね。
楽しみ!
ブックマーク
参考図書
- プログラミング言語Go (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)
- Alan A.A. Donovan (著), Brian W. Kernighan (著), 柴田 芳樹 (翻訳)
- 丸善出版 2016-06-20
- 単行本(ソフトカバー)
- 4621300253 (ASIN), 9784621300251 (EAN), 4621300253 (ISBN), 9784621300251 (ISBN)
- 評価
著者のひとりは(あの「バイブル」とも呼ばれる)通称 “K&R” の K のほうである。この本は Go 言語の教科書と言ってもいいだろう。
-
実行モジュールにディレクトリ・ファイルを埋め込めるパッケージとしては
jteeuwen/go-bindata
やjessevdk/go-assets
が有名だが,これらは最早メンテナンスされていないので使わないほうがいい。 ↩︎ -
たとえば
rakyll/statik
パッケージではファイルシステムの生成・初期化関数fs.New()
の返り値はhttp
.FileSystem
型である。 ↩︎