概要
Goのioパッケージにはio.Reader、io.Writerのインタフェースを有効活用するため以下のような便利なメソッドが用意されています。
しかし普段から使っていないと、これらメソッドの方が簡単にかけるのに忘れて遠回りな書き方をしがちです。
なのでイメージ化して覚えやすいようにします。
図示してみる
ASCII.jp:低レベルアクセスへの入り口(3):io.Reader後編 (2/2)
こちらを参考に図示します。
ポイントは以下です。
- 丸いコネクタが
io.Reader
の送受信 - 三角形のコネクタが
io.Writer
の送受信 - データはすべて左から右に流れる
例えばos.Stdin
、os.Stdout
はこうなります。
io.Copy
io.Copyはio.Readerからデータを読み込み、io.Writerへと書き出します。
なのでos.Stdin、os.Stdoutとそのままくっつけられます。
実際のコード
コードに落とし込むと以下のようになります。
func main() {
io.Copy(os.Stdout, os.Stdin)
}
キーボード(標準入力)にhoge
と入れると、コンソール(標準出力)に吐き出されます。
$ go run main.go
hoge # hogeと入力
hoge
io.Pipe
io.Copyと逆で、io.Writerで書き込まれたらio.Readerから読み出せるようになります。
例えばオブジェクトをjson変換したものを標準出力に吐き出したい場合以下のように組み立てます。
実際のコード
コードに落とし込むと以下のようになります。
type Person struct { Name string `json:"name"` Age int `json:"age"` } func main() { p := Person{"Alice", 20} pr, pw := io.Pipe() go func() { json.NewEncoder(pw).Encode(&p) pw.Close() }() io.Copy(os.Stdout, pr) }
io.Pipe
は内部バッファを持たないので必ずgoroutineで扱いましょう。
$ go run main.go {"name":"Alice","age":20}
io.MultiReader
io.MultiReaderは複数のio.Readerを1つにまとめられます。
引数の順にconcatしていきます。
実際のコード
func main() { header := strings.NewReader("----- HEADER -----\n") content := strings.NewReader("----- CONTENT -----\n") footer := strings.NewReader("----- FOOTER -----\n") mr := io.MultiReader(header, content, footer) io.Copy(os.Stdout, mr) }
こんな感じに繋げてます。
$ go run main.go ----- HEADER ----- ----- CONTENT ----- ----- FOOTER -----
io.MultiWriter
io.MultiWriterは1つのio.Writerを元に複数のio.Writerへ書き出します。
実際のコード
io.MultiWriterを利用することで出力先を標準出力とファイルの複数にしたりできます。
func main() { f, err := os.OpenFile("out", os.O_RDWR|os.O_CREATE, 0755) if err != nil { log.Fatal(err) } defer f.Close() mr := io.MultiWriter(os.Stdout, f) fmt.Fprintf(mr, "hello\n") }
こんな感じに繋げてます。
$ go run main.go hello $ cat out hello
io.TeeReader
io.TeeReaderは通常のio.Readerを読み込まれたら別のio.Writerに書き出すio.Readerへと変換します。
実際のコード
func main() { reader := strings.NewReader("Hello\n") var buffer bytes.Buffer teeReader := io.TeeReader(reader, &buffer) io.Copy(os.Stdout, teeReader) fmt.Printf(buffer.String()) }
こんな感じに繋げてます。
$ go run main.go Hello Hello
先程のio.MultiWriterは書き込んだらio.Writerへと吐き出されましたが、こちらは読み込んだらio.Writerへ吐き出されます。
まとめ
ioパッケージのメソッドは図で理解するとパズルを組み立てるように活用することができます。