GoFile IoIntermediate

bufio.Scanner and bufio.Reader

The `bufio` package provides buffered I/O operations, with `Scanner` for tokenizing input (e.g., line by line) and `Reader` for more granular buffered reading.

Review the syntaxStudy the examplesOpen the coding app
scanner := bufio.NewScanner(r io.Reader)
reader := bufio.NewReader(r io.Reader)

This static page keeps the syntax and examples indexed for search, while the coding app handles interactive exploration and saved references.

What it does

Overview

The `bufio` package provides buffered I/O operations, with `Scanner` for tokenizing input (e.g., line by line) and `Reader` for more granular buffered reading.

The `bufio` package enhances I/O performance by adding buffering capabilities to `io.Reader` and `io.Writer` interfaces. `bufio.Scanner` is designed for simple, efficient reading of input, typically line by line or word by word, making it ideal for parsing text files or standard input. It handles buffering internally and provides an iterator-like interface (`Scan`, `Text`, `Bytes`) that simplifies common parsing tasks. The `Scan` method advances the scanner to the next token, `Text` returns the current token as a string, and `Bytes` returns it as a byte slice. `bufio.Reader`, on the other hand, offers more control over buffered input, allowing operations like `ReadByte`, `Peek`, `ReadString`, and `ReadLine`. It's suitable when you need to read specific amounts of data, look ahead in the stream, or handle more complex parsing logic than `Scanner` provides out-of-the-box. Both types improve performance by reducing the number of underlying system calls to the `io.Reader`.

Time complexity for reading operations generally depends on the underlying `io.Reader` and the size of the buffer. For `Scanner`, `Scan` is typically O(N) where N is the length of the token, but amortized O(1) for small tokens due to buffering. `Reader` methods like `ReadString` can be O(N) where N is the length of the string read. Edge cases include handling large lines that exceed the default buffer size (Scanner might return an error or truncate), and ensuring proper error handling after `Scan` or `Read` calls. Best practices include always checking the error returned by `Scan` or `Read` methods, and for `Scanner`, checking `scanner.Err()` after the loop to catch any errors that occurred during scanning.

Quick reference

Syntax

scanner := bufio.NewScanner(r io.Reader)
reader := bufio.NewReader(r io.Reader)

Inputs

Parameters

rio.Reader · The underlying reader to buffer.

See it in practice

Examples

1

Reading a file line by line with bufio.Scanner

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	file, err := os.Open("example.txt")
	if err != nil {
		fmt.Println("Error opening file:", err)
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	lineNum := 1
	for scanner.Scan() {
		fmt.Printf("Line %d: %s\n", lineNum, scanner.Text())
		lineNum++
	}

	if err := scanner.Err(); err != nil {
		fmt.Println("Error reading file:", err)
	}
}
Output:
Line 1: Hello, Go! Line 2: This is a test file. Line 3: End of content.

This example demonstrates how to use `bufio.Scanner` to read an `os.File` line by line. The `scanner.Scan()` method returns `true` as long as there's a next token (line, by default) and no error occurs. `scanner.Text()` retrieves the current line.

2

Reading a file word by word with bufio.Scanner

package main

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

func main() {
	file, err := os.Open("example.txt")
	if err != nil {
		fmt.Println("Error opening file:", err)
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	scanner.Split(bufio.ScanWords)
	for scanner.Scan() {
		fmt.Printf("Word: %s\n", scanner.Text())
	}

	if err := scanner.Err(); err != nil {
		fmt.Println("Error reading file:", err)
	}
}
Output:
Word: Hello, Word: Go! Word: This Word: is Word: a Word: test Word: file. Word: End Word: of Word: content.

By calling `scanner.Split(bufio.ScanWords)`, the scanner is configured to tokenize the input by words instead of lines. This allows iterating through individual words in the file.

3

Reading until a delimiter with bufio.Reader

package main

import (
	"bufio"
	"fmt"
	"strings"
)

func main() {
	s := "apple,banana,cherry\nhello world"
	r := strings.NewReader(s)
	reader := bufio.NewReader(r)

	line, err := reader.ReadString(',')
	if err != nil {
		fmt.Println("Error reading string:", err)
	}
	fmt.Printf("Read until comma: %q\n", line)

	remaining, err := reader.ReadString('\n')
	if err != nil {
		fmt.Println("Error reading string:", err)
	}
	fmt.Printf("Read until newline: %q\n", remaining)

	peeked, _ := reader.Peek(5)
	fmt.Printf("Peeked 5 bytes: %q\n", string(peeked))
}
Output:
Read until comma: "apple," Read until newline: "banana,cherry\n" Peeked 5 bytes: "hello"

`bufio.Reader` offers methods like `ReadString` to read data until a specific delimiter. `Peek` allows inspecting upcoming bytes without consuming them from the buffer, which is useful for look-ahead parsing.

Debug faster

Common Errors

1

Scanner Buffer Overflow

Cause: A single token (e.g., a very long line) exceeds the default buffer size (typically 64KB) of `bufio.Scanner`.

Fix: Increase the scanner's buffer size using `scanner.Buffer(buf []byte, max int)` or handle the error `bufio.ErrTooLong`.

package main

import (
	"bufio"
	"fmt"
	"strings"
)

func main() {
	longLine := strings.Repeat("a", 70000) // Exceeds default 64KB
	r := strings.NewReader(longLine)
	scanner := bufio.NewScanner(r)

	// Uncomment to fix:
	// const maxCapacity = 1024 * 1024 // 1MB
	// buf := make([]byte, maxCapacity)
	// scanner.Buffer(buf, maxCapacity)

	if !scanner.Scan() {
		if err := scanner.Err(); err != nil {
			fmt.Println("Error during scan:", err) // bufio.ErrTooLong
		}
	}
}

Runtime support

Compatibility

Go runtimeN/AGo 1.0+

Source: Go Standard Library Documentation

Common questions

Frequently Asked Questions

The `bufio` package provides buffered I/O operations, with `Scanner` for tokenizing input (e.g., line by line) and `Reader` for more granular buffered reading.

r: The underlying reader to buffer.

Scanner Buffer Overflow: Increase the scanner's buffer size using `scanner.Buffer(buf []byte, max int)` or handle the error `bufio.ErrTooLong`.