Learn Go← Dashboard

fmt, io, os, bufio, encoding/json, net/http, time, slog, regexp, flag, embed.

bufio — Buffered I/O & Scanners

Raw io.Reader/io.Writer are unbuffered: every call may translate to a syscall. bufio wraps them with an in-memory buffer so you can read line-by-line, token by token, or just batch tiny writes into one big one.

bufio.Scanner — line-at-a-time input

Scanner is the easiest way to walk text. Default split function is by line.

go playground
Loading...
  • Scan() returns false when input is done or when something errored.
  • Text() is the current token without the trailing newline.
  • Always check scanner.Err() after the loop — Scan returning false doesn't tell you whether it was EOF or a real failure.

Tokenizing words

Swap the split function to walk words, runes, or your own custom delimiter:

scanner.Split(bufio.ScanWords)
for scanner.Scan() {
    fmt.Println(scanner.Text())
}

Built-ins: ScanLines (default), ScanWords, ScanRunes, ScanBytes.

bufio.Reader — when you need more control

Reader is the heavier-duty cousin. It can peek, read exact byte counts, and read up to a delimiter of your choice:

r := bufio.NewReader(conn)
line, err := r.ReadString('\n')   // includes the '\n'
b, err := r.ReadByte()
peek, err := r.Peek(4)            // look without consuming

bufio.Writer — batch small writes

Every os.Stdout.Write is a syscall. Wrap with bufio.Writer and many small writes become one:

w := bufio.NewWriter(os.Stdout)
defer w.Flush()           // never forget Flush — buffered bytes are lost otherwise
for i := 0; i < 1000; i++ {
    fmt.Fprintln(w, "line", i)
}

When to reach for bufio

  • Reading user input or stdin line-by-line? → bufio.Scanner.
  • Parsing a protocol with mixed reads (peek a header, then read N bytes)? → bufio.Reader.
  • Writing many small chunks to a file or network? → bufio.Writer.
  • One-shot read of a whole small file? → os.ReadFile is simpler.
You scan a file with `bufio.Scanner` and the loop ends after only two lines, but you expected ten. The first thing to check is: