次期 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 で実行モジュールへの任意のファイルの埋め込み機能が公式にサポートされるらしい。

うまくすればこの記事の io/fs パッケージとも将来的に統合されるかもね。 楽しみ!

ブックマーク

参考図書

photo
プログラミング言語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 言語の教科書と言ってもいいだろう。

reviewed by Spiegel on 2016-07-13 (powered by PA-APIv5)


  1. 実行モジュールにディレクトリ・ファイルを埋め込めるパッケージとしては jteeuwen/go-bindatajessevdk/go-assets が有名だが,これらは最早メンテナンスされていないので使わないほうがいい。 ↩︎

  2. たとえば rakyll/statik パッケージではファイルシステムの生成・初期化関数 fs.New() の返り値は http.FileSystem 型である。 ↩︎