bufio.NewScanner în Go

Creează un bufio.Scanner, cel mai simplu mod de a citi un text rând cu rând (sau cuvânt cu cuvânt).

Sintaxă
func NewScanner(r io.Reader) *Scanner

s := bufio.NewScanner(r)
for s.Scan() {
    rand := s.Text()
}
if err := s.Err(); err != nil { ... }

Ce face bufio.NewScanner

bufio.Scanner împarte o sursă în „bucăți” (token-uri): implicit rânduri. Bucla clasică este for s.Scan() { ... s.Text() ... }: Scan trece la bucata următoare și returnează false la final, iar Text dă bucata curentă, fără \n (și fără \r din fișierele Windows).

După buclă verifici s.Err(): Scan returnează false și la sfârșitul datelor, și la o eroare. Cu s.Split(bufio.ScanWords) împarte pe cuvinte, cu bufio.ScanRunes pe caractere.

Limita implicită pentru o bucată este 64 KB. Un rând mai lung oprește scanarea cu eroarea bufio.ErrTooLong; o mărești cu s.Buffer, iar pentru date fără limită folosește bufio.Reader.

Parametri

Parametru Descriere
r Sursa: os.Stdin, un fișier, un strings.Reader, o conexiune.

Ce returnează

Un *bufio.Scanner nou, care împarte pe rânduri.

Exemple

Exemplul 1: Un fișier, rând cu rând

package main

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

func main() {
    os.WriteFile("cumparaturi.txt", []byte("pâine\nlapte\nouă\nmere\n"), 0o644)
    f, err := os.Open("cumparaturi.txt")
    if err != nil {
        fmt.Println("eroare:", err)
        return
    }
    defer f.Close()

    s := bufio.NewScanner(f)
    nr := 0
    for s.Scan() {
        nr++
        fmt.Printf("%d. %s\n", nr, s.Text())
    }
    if err := s.Err(); err != nil {
        fmt.Println("eroare la citire:", err)
    }
}

Rezultat

1. pâine
2. lapte
3. ouă
4. mere

Exemplul 2: Suma numerelor de la tastatură

Citim până la un rând gol; rândurile care nu sunt numere sunt semnalate.

package main

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

func main() {
    s := bufio.NewScanner(os.Stdin)
    suma := 0.0
    for s.Scan() {
        linie := strings.TrimSpace(s.Text())
        if linie == "" {
            break
        }
        x, err := strconv.ParseFloat(linie, 64)
        if err != nil {
            fmt.Printf("„%s” nu este un număr, îl sar\n", linie)
            continue
        }
        suma += x
    }
    fmt.Printf("Total: %.2f lei\n", suma)
}

Ce scrie utilizatorul (intrare)

12.50
7
zece
30.25

Rezultat

„zece” nu este un număr, îl sar
Total: 49.75 lei

Greșeli frecvente

  • Nu verifici s.Err() după buclă. Un rând prea lung sau o eroare de citire arată la fel ca sfârșitul fișierului.
  • Folosești Scanner pentru fișiere cu rânduri de peste 64 KB (JSON minimizat, jurnale). Scanarea se oprește cu „token too long”; mărește limita cu Buffer.
  • Creezi un Scanner nou pe os.Stdin la fiecare citire. Fiecare poate „înghiți” în buffer rânduri destinate celuilalt.

Comenzi înrudite

  • bufio.Scanner.Scan: Trece la următoarea bucată (rând, cuvânt) din sursă; returnează false când nu mai sunt date sau a apărut o eroare.
  • bufio.Scanner.Text: Text returnează bucata curentă găsită de Scan, ca string; Bytes o returnează ca []byte, fără copiere.
  • bufio.Scanner.Err: Returnează eroarea care a oprit scanarea, sau nil dacă s-a ajuns normal la sfârșitul datelor.
  • bufio.Scanner.Split: Alege cum împarte Scanner-ul datele: pe rânduri (implicit), cuvinte, caractere, octeți sau după o regulă proprie.
  • bufio.Scanner.Buffer: Setează buffer-ul inițial și dimensiunea maximă a unei bucăți, ca să poți citi rânduri mai lungi de 64 KB.
  • bufio.NewReader: Învelește un io.Reader într-un bufio.Reader, care citește pe blocuri și oferă ReadString, ReadRune, ReadLine.