fs.FS を使ってディレクトリ・ファイルを参照する
仕事で簡単なファイル操作のコードを書いたのだが io/fs
パッケージの使い方をド忘れして往生したので,忘れないうちにメモっておく。
まずは基本形
まず,以下のディレクトリ・ファイルがあるとする。
$ tree testdata
testdata
├── hello1.txt
├── hello2.txt
└── hello3.txt
この testdata/*.txt
ファイルの内容を標準出力に片っ端から出力するという簡単なお仕事。
なお,表示順は考慮しないものとする。
やりかたは色々あると思うが,今回は io/fs
パッケージを使ったやり方でやってみる。
package main
import (
"fmt"
"io"
"io/fs"
"os"
)
func output(fileSystem fs.FS) error {
paths, err := fs.Glob(fileSystem, "*.txt")
if err != nil {
return err
}
for _, path := range paths {
if _, err := func(path string) (int64, error) {
f, err := fileSystem.Open(path)
if err != nil {
return 0, err
}
defer f.Close()
return io.Copy(os.Stdout, f)
}(path); err != nil {
return err
}
}
return nil
}
func main() {
if err := output(os.DirFS("testdata")); err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
}
手順としては
os
.DirFS()
関数でtestdata
ディレクトリのfs
.FS
型インスタンスを取得してoutput()
関数に渡すoutput()
関数ではfs
.Glob()
関数で"*.txt"
にマッチするファイルの一覧を取得し,順にファイル内容を標準出力にコピーする
という感じ。
各ファイルのオープンからクローズまでの処理を無名関数1 として囲っているのは defer f.Close()
を使いたかったから。
深い意味はない。
さて,この output()
関数を変えることなく通常のファイル以外のファイルシステムで応用してみる。
埋め込みファイルシステム
次は embed
パッケージでディレクトリ・ファイルを埋め込んだ場合。
main
関数のみ書いておく。
パッケージのインポートは適当に補完してね(標準パッケージしか使ってないので無問題)。
//go:embed testdata/*.txt
var assets embed.FS
func main() {
fileSystem, err := fs.Sub(assets, "testdata")
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
if err := output(fileSystem); err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
}
上のコードでは assets
ファイルシステムのルートが testdata
の親ディレクトリになるので fs
.Sub()
関数で testdata
ディレクトリに下りてから output()
関数に渡している。
Zip ファイルシステム
今度は testdata
ディレクトリを zip 圧縮した testdata.zip
を読み込む場合。
これも main
関数のみ書いておく。
func main() {
rc, err := zip.OpenReader("./testdata.zip")
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
defer rc.Close()
fileSystem, err := fs.Sub(rc, "testdata")
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
if err := output(fileSystem); err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
}
zip
.OpenReader()
関数は *
zip
.ReadCloser
型のインスタンスを返すのだが,これが fs
.FS
interface 型と互換があるため,そのまま 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 言語の教科書と言ってもいいだろう。
- デベロッパーゴースーパーゴラン Tシャツ
- Geek Go Super Golang Tees
- ウェア&シューズ
- B09C2XBC2F (ASIN)
- 評価
ついカッとなってポチった。反省はしない