ZetCode

Golang fmt.Fscanf function

last modified May 8, 2025

This tutorial explains how to use the fmt.Fscanf function in Go. We'll cover input parsing basics with practical examples of formatted scanning.

The fmt.Fscanf function scans input from a reader according to a format specifier. It parses values separated by whitespace into variables. This is useful for reading structured data from files or other input sources.

In Go, fmt.Fscanf is similar to fmt.Scanf but works with any io.Reader instead of standard input. It returns the number of items successfully scanned and any error encountered.

Basic Fscanf example

The simplest use of fmt.Fscanf reads values from a string reader. This example demonstrates basic formatted scanning.
Note: The format string must match the input structure exactly.

basic_fscanf.go
package main

import (
    "fmt"
    "strings"
)

func main() {
    input := "John 25 50000.50"
    reader := strings.NewReader(input)
    
    var name string
    var age int
    var salary float64
    
    n, err := fmt.Fscanf(reader, "%s %d %f", &name, &age, &salary)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    
    fmt.Printf("Scanned %d items: %s, %d, %.2f\n", 
        n, name, age, salary)
}

The code reads a string, integer, and float from the input. The format string specifies the expected types, and variables must be passed as pointers.

Reading from a file

fmt.Fscanf is commonly used to read structured data from files. This example shows how to parse data from a text file.

file_fscanf.go
package main

import (
    "fmt"
    "os"
)

func main() {
    file, err := os.Open("data.txt")
    if err != nil {
        fmt.Println("Error opening file:", err)
        return
    }
    defer file.Close()
    
    var id int
    var product string
    var price float64
    
    for {
        n, err := fmt.Fscanf(file, "%d %s %f\n", &id, &product, &price)
        if err != nil {
            break
        }
        fmt.Printf("Read %d items: %d %s %.2f\n", n, id, product, price)
    }
}

The code reads multiple records from a file in a loop. Each line contains an integer, string, and float value separated by spaces.

Handling different formats

fmt.Fscanf can parse various input formats. This example shows different format specifiers in action.

formats_fscanf.go
package main

import (
    "fmt"
    "strings"
)

func main() {
    input := "Date: 2023-05-15 Time: 14:30 Value: 42.7%"
    reader := strings.NewReader(input)
    
    var year, month, day, hour, minute int
    var value float64
    var unit string
    
    n, err := fmt.Fscanf(reader, "Date: %d-%d-%d Time: %d:%d Value: %f%%%s",
        &year, &month, &day, &hour, &minute, &value, &unit)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    
    fmt.Printf("Scanned %d items: %d-%02d-%02d %02d:%02d %.1f%%\n",
        n, year, month, day, hour, minute, value)
}

The format string includes literal text that must match the input exactly. Special characters like % must be escaped with another % in the format.

Reading multiple lines

fmt.Fscanf can process multi-line input by including newlines in the format string. This example demonstrates multi-line parsing.

multiline_fscanf.go
package main

import (
    "fmt"
    "strings"
)

func main() {
    input := `Person:
Name: Alice
Age: 30
Occupation: Engineer
`
    reader := strings.NewReader(input)
    
    var name, occupation string
    var age int
    
    _, err := fmt.Fscanf(reader, `Person:
Name: %s
Age: %d
Occupation: %s
`, &name, &age, &occupation)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    
    fmt.Printf("%s is a %d-year-old %s\n", name, age, occupation)
}

The format string includes newlines to match the input structure. Backticks are used for raw string literals to preserve the formatting.

Error handling

Proper error handling is crucial when using fmt.Fscanf. This example shows how to handle various scanning errors.

error_fscanf.go
package main

import (
    "fmt"
    "strings"
)

func main() {
    tests := []string{
        "100 200",              // OK
        "100 abc",              // type mismatch
        "100",                  // not enough values
        "100 200 300",         // extra values
    }
    
    for _, input := range tests {
        reader := strings.NewReader(input)
        var a, b int
        
        n, err := fmt.Fscanf(reader, "%d %d", &a, &b)
        fmt.Printf("Input: %q\n", input)
        fmt.Printf("Scanned %d items: %d, %d\n", n, a, b)
        
        if err != nil {
            fmt.Println("Error:", err)
        }
        fmt.Println("-----")
    }
}

The code tests different error scenarios. fmt.Fscanf returns the number of successfully scanned items and any error encountered.

Reading into a struct

fmt.Fscanf can populate struct fields directly. This example shows structured data parsing.

struct_fscanf.go
package main

import (
    "fmt"
    "strings"
)

type Employee struct {
    ID     int
    Name   string
    Salary float64
}

func main() {
    input := "101 Bob 75000.50"
    reader := strings.NewReader(input)
    
    var emp Employee
    
    n, err := fmt.Fscanf(reader, "%d %s %f", 
        &emp.ID, &emp.Name, &emp.Salary)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    
    fmt.Printf("Scanned %d items: %+v\n", n, emp)
}

The struct fields are passed as pointers to fmt.Fscanf. The %+v verb prints the struct with field names.

Custom reader example

fmt.Fscanf works with any type implementing io.Reader. This example uses a custom reader implementation.

custom_reader.go
package main

import (
    "fmt"
    "io"
)

type ByteReader struct {
    data []byte
    pos  int
}

func (r *ByteReader) Read(p []byte) (n int, err error) {
    if r.pos >= len(r.data) {
        return 0, io.EOF
    }
    n = copy(p, r.data[r.pos:])
    r.pos += n
    return n, nil
}

func main() {
    data := []byte("3.14 42 hello")
    reader := &ByteReader{data: data}
    
    var pi float64
    var num int
    var word string
    
    n, err := fmt.Fscanf(reader, "%f %d %s", &pi, &num, &word)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    
    fmt.Printf("Scanned %d items: %.2f %d %s\n", n, pi, num, word)
}

The custom ByteReader implements the io.Reader interface. fmt.Fscanf works with it just like any other reader.

Source

Go fmt package documentation

This tutorial covered the fmt.Fscanf function in Go with practical examples of formatted input parsing from various sources.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Golang tutorials.