search
LoginSignup
6

More than 3 years have passed since last update.

posted at

updated at

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

はじめに

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)

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
What you can do with signing up
6