🙌

【Go】bytes.Bufferを活用

2022/08/11に公開

そもそも、bytes.Bufferは何なのでしょうか。

bytesのパッケージドキュメントには、

A Buffer is a variable-sized buffer of bytes with Read and Write methods. The zero value for Buffer is an empty buffer ready to use.

と説明されています。
https://pkg.go.dev/bytes#Buffer

上記の通り、*bytes.Bufferは、Goでお馴染みインターフェースのio.Readerとio.Writerを実装しています。
aws-sdk-goを用いて、S3へ画像をアップロードするときに、byteスライスを例えば以下のように変換することがあるでしょう。

// ここではdataをバイト列と仮定
b := new(bytes.Buffer)
b.Write(data)

uploader := &s3manager.UploadInput{
	// Bodyはio.Readerを受け入れる
	Body:        b,
	以下つづく...
}

Bodyはio.Readerな必要があるため、このような場面でbytes.Bufferを活用できます。

(そうだ、bytes.Buffer関連のメソッドを簡単にまとめてみよう。)

func (b *Buffer) WriteTo(w io.Writer) (n int64, err error)

WriteToメソッドはバッファの中身が空になるかエラーが発生するまで、引数のwにデータを書き込みます。返り値のnは、書き込んだバイトの数になります。

package main

import (
	"bytes"
	"fmt"
	"os"
)

func main() {
	buf := bytes.NewBuffer([]byte("HANABI"))

	// os.Stdoutを指定しているため、標準出力で「HANABI」と表示される
	if _, err := buf.WriteTo(os.Stdout); err != nil {
		fmt.Println(err)
	}
}

func (*Buffer) Grow(n int)

Growメソッドで、バッファのサイズを上げることができます。別の割り当てをすることなしに、少なくとも引数のnバイトをバッファに書き込むことができます。読み込みが遅い場合などに指定。

package main

import (
	"bytes"
	"fmt"
)

func main() {
	buf := new(bytes.Buffer)

	buf.Grow(64)

	b := buf.Bytes()

	buf.Write([]byte("64 bytes or fewer"))
	
	// output: 64 bytes or fewer
	fmt.Printf("%q", b[:buf.Len()])
}

func (*Buffer) Reset

Resetメソッドは、バッファを空にします。

package main

import (
	"bytes"
	"fmt"
)

func main() {
	buf := bytes.NewBuffer([]byte("HANABI"))
	fmt.Printf("string: %s len: %v\n", buf.String(), buf.Len())

	buf.Reset()
	fmt.Printf("string: %s len: %v", buf.String(), buf.Len())
}

func (*Buffer) Truncate(n int)

Truncateメソッドは、バッファから最初のnバイトを除く全てのバイトを破棄します。
ちなみに、内部の実装は以下のようになっています。0の場合はResetが実行されます。

func (b *Buffer) Truncate(n int) {
	if n == 0 {
		b.Reset()
		return
	}
	b.lastRead = opInvalid
	if n < 0 || n > b.Len() {
		panic("bytes.Buffer: truncation out of range")
	}
	b.buf = b.buf[:b.off+n]
}

もう少しつらつらと書いていこうと思ったけど、もうこんな時間だから一旦眠ります😪

Discussion