fmt.Fscan în Go

Citește valori dintr-un io.Reader (fișier, buffer, os.Stdin) în variabile, ca Scan, Scanf și Scanln.

Sintaxă
func Fscan(r io.Reader, a ...any) (n int, err error)
func Fscanf(r io.Reader, format string, a ...any) (n int, err error)
func Fscanln(r io.Reader, a ...any) (n int, err error)

Ce face fmt.Fscan

Fscan, Fscanf și Fscanln citesc din sursa dată ca prim argument, nu neapărat de la tastatură: un fișier deschis, un strings.Reader, os.Stdin. De fapt, fmt.Scan(&x) este fmt.Fscan(os.Stdin, &x).

În concursurile de programare se folosește des fmt.Fscan(in, &x) cu in := bufio.NewReader(os.Stdin): bufferul face citirea a mii de numere mult mai rapidă decât fmt.Scan direct.

Fiecare apel citește doar cât îi trebuie; restul rămâne în sursă pentru apelul următor.

Parametri

Parametru Descriere
r io.Reader Sursa: orice tip cu metoda Read.
format Doar la Fscanf: șablonul cu verbe.
a ...any Pointerii la variabile.

Ce returnează

Numărul de valori citite și eroarea (io.EOF când sursa s-a terminat).

Exemple

Exemplul 1: Citirea unui tabel dintr-un text

strings.NewReader transformă un text într-un io.Reader. Bucla citește câte trei valori până la sfârșit.

package main

import (
	"fmt"
	"strings"
)

func main() {
	date := strings.NewReader("Ana 10 Iași\nIon 8 Cluj\nMaria 9 Brașov\n")
	for {
		var nume, oras string
		var nota int
		_, err := fmt.Fscan(date, &nume, &nota, &oras)
		if err != nil {
			break
		}
		fmt.Printf("%-6s %2d %s\n", nume, nota, oras)
	}
}

Rezultat

Ana    10 Iași
Ion     8 Cluj
Maria   9 Brașov

Exemplul 2: Citire rapidă de la tastatură cu bufio

Primul număr spune câte numere urmează. Varianta cu bufio.NewReader este cea recomandată pentru intrări mari.

package main

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

func main() {
	in := bufio.NewReader(os.Stdin)
	var n int
	fmt.Fscan(in, &n)
	maxim := 0
	for i := 0; i < n; i++ {
		var x int
		fmt.Fscan(in, &x)
		maxim = max(maxim, x)
	}
	fmt.Println("cel mai mare:", maxim)
}

Ce scrie utilizatorul (intrare)

5
12 7 45
3 18

Rezultat

cel mai mare: 45

Exemplul 3: Fscanf și Fscanln rând cu rând

package main

import (
	"fmt"
	"strings"
)

func main() {
	r := strings.NewReader("ora 14:30\nTimișoara 2026\n")
	var h, m int
	n, err := fmt.Fscanf(r, "ora %d:%d\n", &h, &m)
	fmt.Println(n, err, "->", h, "și", m, "minute")

	var oras string
	var an int
	n, err = fmt.Fscanln(r, &oras, &an)
	fmt.Println(n, err, "->", oras, an)
}

Rezultat

2 <nil> -> 14 și 30 minute
2 <nil> -> Timișoara 2026

Greșeli frecvente

  • Creezi un bufio.NewReader(os.Stdin) nou la fiecare citire. Datele deja citite în bufferul vechi se pierd; creează-l o singură dată.
  • Amesteci fmt.Scan (direct din os.Stdin) cu fmt.Fscan(in, …) pe un bufio.Reader. Bufferul a citit deja înainte, așa că valorile ajung în ordine greșită.

Comenzi înrudite

  • fmt.Scan: Citește valori de la tastatură (intrarea standard) în variabile; Scanln se oprește la capăt de rând, Scanf folosește un format.
  • fmt.Sscanf: Citește valori dintr-un text (string) în variabile, ca Scan, Scanf și Scanln, dar fără tastatură.
  • strings.Reader: Face dintr-un text o sursă de citire (io.Reader), ca să-l dai funcțiilor care citesc din fișiere sau rețea.