What are the pitfalls of bufio.Scanner and bufio.Writer?
Question 460MediumGo 1.22 to 1.25
Scanner: the default max token size is 64 KB (bufio.MaxScanTokenSize). A longer line makes Scan() return false, and unless you check sc.Err() (which is bufio.ErrTooLong) you silently process a truncated file. Also, sc.Bytes() returns a slice into the internal buffer that is overwritten on the next Scan — copy it if you keep it.
sc := bufio.NewScanner(f)
sc.Buffer(make([]byte, 0, 64*1024), 10*1024*1024) // allow 10 MB lines
var lines [][]byte
for sc.Scan() {
lines = append(lines, bytes.Clone(sc.Bytes())) // copy!
}
if err := sc.Err(); err != nil {
return err
}
For arbitrary-length lines, use bufio.Reader.ReadString('\n') or ReadLine. sc.Split(bufio.ScanWords) changes tokenization.
Writer: data sits in a 4 KB buffer until full; forgetting Flush() loses the tail. Errors are sticky: once a write fails, all subsequent writes return the same error, so checking Flush's error is enough.
w := bufio.NewWriter(f)
for _, l := range lines {
w.Write(l)
w.WriteByte('\n')
}
if err := w.Flush(); err != nil {
return err
}
return f.Close() // Close error matters for writes, tooMore on Standard Library, HTTP & Systems Design in Go
- Q458What is the exact io.Reader contract? What's wrong with this read loop?
- Q459Compose io primitives: upload a file to HTTP while computing its SHA-256 and limiting size, without buffering it in memory.
- Q461Implement graceful shutdown for an HTTP server with background workers.
- Q462How does log/slog work? Discuss handlers, attributes, LogValuer, and performance.
- Q463What does this print? Explain the monotonic clock and time.Time comparison.
- Q464time.Ticker, time.After and timers: what leaks, and what changed in Go 1.23?