LoginSignup
12
6

More than 5 years have passed since last update.

1つのstreamから複数回読み込みを行う

Last updated at Posted at 2018-07-18

はじめに

GolangでのCLIツール作成の練習として画像をリサイズしてくれるツールを作っていた際に、1つのstreamから複数回読み込みを行う必要がでてきたのでその備忘録

なぜ複数回の読み込みが必要?

  • 画像の形式に関しては利用者側は意識しなくても良いようにimage.Decode()で取得できるformatを使い処理を条件分岐してました。(この処理で1つの読み込みが必要
img, format, _ := image.Decode(in)

switch format {
  case "png":
  • pngjpegに関してはimage.Decodeで取得できるImageインスタンスをそれ移行の処理で使えばいいだけなのですが、gifgif.DecodeAll()という別の関数を呼び出す必要があるらしく、こちらの引数がio.Readerでした(2つ目

どうしたのか

buf := bytes.NewBuffer(nil)
gifDecodeTarget := bytes.NewBuffer(nil)

w := io.MultiWriter(buf, gifDecodeTarget)
io.Copy(w, in)

img, format, err := image.Decode(buf)

switch format {
case "gif":
  gifimg, err := gif.DecodeAll(gifDecodeTarget)

io.MultiWriterを使うことで複数のoutに対して書き込みができるので、io.Copyを利用してinを複数のout(両方ともBuffer)に書き込み、bytes.BufferはRead関数を持ってるためio.Readerを満たしているので、読み込みが必要な場面で利用していきました

その他指摘いただいた方法

Seekを使うパターン

Seekerが実装されているos.Fileなどで受け取ること前提になってしまいますが、Seekを使うパターン

img, format, err := image.Decode(in)

switch format {
case "gif":
  in.Seek(0, 0) // インデックスを先頭に戻す
  gifimg, err := gif.DecodeAll(in)

io.TeeReaderを使うパターン

こちらだとio.Readerのまま行けそうです

buf := bytes.NewBuffer(nil)
r := io.TeeReader(in, buf)
img, format, err := image.Decode(r) // このタイミングでbufに書き込みが走る

switch format {
case "gif":
  gifimg, err := gif.DecodeAll(buf)
12
6
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
6