Skip to main content

Overview

Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer object, creating another object (Reader or Writer) that also implements the interface but provides buffering and some help for textual I/O.

Buffered Reading

NewReader

Returns a new Reader whose buffer has the default size (4096 bytes).
func NewReader(rd io.Reader) *Reader
rd
io.Reader
required
Underlying reader to buffer
reader
*Reader
Buffered reader
Example:
file, _ := os.Open("data.txt")
defer file.Close()

reader := bufio.NewReader(file)
line, _ := reader.ReadString('\n')
fmt.Print(line)

NewReaderSize

Returns a new Reader whose buffer has at least the specified size.
func NewReaderSize(rd io.Reader, size int) *Reader
rd
io.Reader
required
Underlying reader
size
int
required
Buffer size in bytes
Example:
reader := bufio.NewReaderSize(file, 8192) // 8KB buffer

Reader.Read

Reads data into p.
func (b *Reader) Read(p []byte) (n int, err error)
p
[]byte
required
Buffer to read into
n
int
Number of bytes read
err
error
Error encountered

Reader.ReadByte

Reads and returns a single byte.
func (b *Reader) ReadByte() (byte, error)
Example:
b, err := reader.ReadByte()
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Read byte: %c\n", b)

Reader.ReadString

Reads until the first occurrence of delim in the input.
func (b *Reader) ReadString(delim byte) (string, error)
delim
byte
required
Delimiter byte to read until
line
string
String containing data up to and including the delimiter
err
error
Error (often io.EOF)
Example:
line, err := reader.ReadString('\n')
if err != nil && err != io.EOF {
    log.Fatal(err)
}
fmt.Print(line)

Reader.ReadBytes

Reads until the first occurrence of delim, returning a byte slice.
func (b *Reader) ReadBytes(delim byte) ([]byte, error)
Example:
data, err := reader.ReadBytes('\n')

Reader.ReadLine

Low-level line-reading primitive. Most callers should use ReadBytes(‘\n’) or ReadString(‘\n’) instead.
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
line
[]byte
Line data (without newline)
isPrefix
bool
True if line was too long for buffer
err
error
Error encountered

Reader.Peek

Returns the next n bytes without advancing the reader.
func (b *Reader) Peek(n int) ([]byte, error)
n
int
required
Number of bytes to peek
Example:
data, err := reader.Peek(10)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Next 10 bytes: %s\n", data)

Reader.Buffered

Returns the number of bytes that can be read from the current buffer.
func (b *Reader) Buffered() int
Example:
n := reader.Buffered()
fmt.Printf("%d bytes buffered\n", n)

Buffered Writing

NewWriter

Returns a new Writer whose buffer has the default size.
func NewWriter(w io.Writer) *Writer
w
io.Writer
required
Underlying writer to buffer
Example:
file, _ := os.Create("output.txt")
defer file.Close()

writer := bufio.NewWriter(file)
writer.WriteString("Hello, World!\n")
writer.Flush() // Important: flush to write buffered data

NewWriterSize

Returns a new Writer whose buffer has at least the specified size.
func NewWriterSize(w io.Writer, size int) *Writer
w
io.Writer
required
Underlying writer
size
int
required
Buffer size in bytes

Writer.Write

Writes the contents of p into the buffer.
func (b *Writer) Write(p []byte) (nn int, err error)
p
[]byte
required
Data to write
nn
int
Number of bytes written
err
error
Error if write is short

Writer.WriteByte

Writes a single byte.
func (b *Writer) WriteByte(c byte) error
Example:
err := writer.WriteByte('A')

Writer.WriteString

Writes a string.
func (b *Writer) WriteString(s string) (int, error)
s
string
required
String to write
Example:
n, err := writer.WriteString("Hello, World!\n")
if err != nil {
    log.Fatal(err)
}

Writer.WriteRune

Writes a single Unicode code point.
func (b *Writer) WriteRune(r rune) (size int, err error)
r
rune
required
Rune to write
Example:
size, err := writer.WriteRune('')

Writer.Flush

Writes any buffered data to the underlying io.Writer.
func (b *Writer) Flush() error
Example:
writer.WriteString("data")
err := writer.Flush() // Ensure data is written
if err != nil {
    log.Fatal(err)
}

Writer.Available

Returns how many bytes are unused in the buffer.
func (b *Writer) Available() int

Writer.Buffered

Returns the number of bytes that have been written into the current buffer.
func (b *Writer) Buffered() int

Scanner

NewScanner

Returns a new Scanner to read from r.
func NewScanner(r io.Reader) *Scanner
r
io.Reader
required
Reader to scan
Example:
file, _ := os.Open("data.txt")
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
    fmt.Println(scanner.Text())
}

if err := scanner.Err(); err != nil {
    log.Fatal(err)
}

Scanner.Scan

Advances the Scanner to the next token.
func (s *Scanner) Scan() bool
hasNext
bool
True if there is a token to read

Scanner.Text

Returns the most recent token as a string.
func (s *Scanner) Text() string
Example:
for scanner.Scan() {
    line := scanner.Text()
    fmt.Println(line)
}

Scanner.Bytes

Returns the most recent token as a byte slice.
func (s *Scanner) Bytes() []byte

Scanner.Err

Returns the first non-EOF error encountered by the Scanner.
func (s *Scanner) Err() error
Example:
for scanner.Scan() {
    // process
}
if err := scanner.Err(); err != nil {
    log.Fatal(err)
}

Scanner.Split

Sets the split function for the Scanner.
func (s *Scanner) Split(split SplitFunc)
split
SplitFunc
required
Function to tokenize input. Default is ScanLines.
Example:
scanner := bufio.NewScanner(reader)
scanner.Split(bufio.ScanWords) // Split on words instead of lines

for scanner.Scan() {
    word := scanner.Text()
    fmt.Println(word)
}

Split Functions

Predefined split functions for Scanner:
  • ScanBytes - Returns each byte as a token
  • ScanRunes - Returns each UTF-8 encoded rune as a token
  • ScanWords - Returns each space-separated word as a token
  • ScanLines - Returns each newline-terminated line as a token (default)

Complete Example

package main

import (
    "bufio"
    "fmt"
    "log"
    "os"
    "strings"
)

func main() {
    // Writing with bufio
    file, err := os.Create("output.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()
    
    writer := bufio.NewWriter(file)
    writer.WriteString("Line 1\n")
    writer.WriteString("Line 2\n")
    writer.WriteString("Line 3\n")
    writer.Flush() // Important!
    
    // Reading line by line
    file, _ = os.Open("output.txt")
    defer file.Close()
    
    reader := bufio.NewReader(file)
    for {
        line, err := reader.ReadString('\n')
        if err != nil {
            break
        }
        fmt.Print(line)
    }
    
    // Using Scanner
    input := "word1 word2 word3"
    scanner := bufio.NewScanner(strings.NewReader(input))
    scanner.Split(bufio.ScanWords)
    
    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }
    
    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }
}

Performance Tips

  • Always call Flush() on Writer before closing the underlying writer
  • Use Scanner for simple line-by-line or word-by-word reading
  • Use Reader methods for more control over buffering
  • Adjust buffer size with NewReaderSize/NewWriterSize for optimal performance
  • Scanner is more convenient but Reader gives more control

Build docs developers (and LLMs) love