encoding/csv.Reader în Go

Citește fișiere CSV rând cu rând: NewReader creează cititorul, Read returnează următorul rând ca []string.

Sintaxă
import "encoding/csv"

func NewReader(r io.Reader) *Reader
func (r *Reader) Read() (record []string, err error)

// câmpuri utile: Comma, Comment, FieldsPerRecord, TrimLeadingSpace, LazyQuotes

Ce face encoding/csv.Reader

csv.NewReader(r) creează un cititor CSV peste orice io.Reader (fișier deschis, text, corpul unei cereri). rd.Read() returnează următorul rând ca slice de texte (câte unul pe coloană) și io.EOF când nu mai sunt rânduri. Câmpurile între ghilimele pot conține virgule, ghilimele dublate ("") și chiar rânduri noi.

Setări prin câmpuri, înainte de prima citire: Comma schimbă separatorul (în Excel românesc este adesea ';'), Comment ignoră rândurile care încep cu un caracter (de exemplu '#'), TrimLeadingSpace elimină spațiile de la începutul câmpurilor, FieldsPerRecord verifică numărul de coloane (implicit, toate rândurile trebuie să aibă câte coloane are primul; -1 dezactivează verificarea).

Citirea rând cu rând consumă puțină memorie, deci este potrivită pentru fișiere mari. Erorile de format sunt de tip *csv.ParseError și spun rândul și coloana.

Parametri

Parametru Descriere
r Sursa datelor (io.Reader).

Ce returnează

NewReader: *csv.Reader. Read: rândul ([]string) și o eroare (io.EOF la final).

Exemple

Exemplul 1: Citire rând cu rând

package main

import (
	"encoding/csv"
	"errors"
	"fmt"
	"io"
	"strconv"
	"strings"
)

func main() {
	date := `nume,oras,salariu
Ana Popescu,Iași,6500
"Ionescu, Mihai",Cluj,7200
Elena,"Târgu Mureș",5800
`
	rd := csv.NewReader(strings.NewReader(date))
	antet, err := rd.Read()
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("Coloane:", antet)

	total := 0
	for {
		rand, err := rd.Read()
		if errors.Is(err, io.EOF) {
			break
		}
		if err != nil {
			fmt.Println("eroare:", err)
			return
		}
		salariu, _ := strconv.Atoi(rand[2])
		total += salariu
		fmt.Printf("%-16s %-12s %d lei\n", rand[0], rand[1], salariu)
	}
	fmt.Println("Total salarii:", total, "lei")
}

Rezultat

Coloane: [nume oras salariu]
Ana Popescu      Iași         6500 lei
Ionescu, Mihai   Cluj         7200 lei
Elena            Târgu Mureș  5800 lei
Total salarii: 19500 lei

Exemplul 2: Separator ; și comentarii (export din Excel)

package main

import (
	"encoding/csv"
	"fmt"
	"strings"
)

func main() {
	date := `# export produse, 19.10.2026
cod; produs; pret
101; Cafea boabe 1kg; 89,90
102; Ceai verde; 14,50
`
	rd := csv.NewReader(strings.NewReader(date))
	rd.Comma = ';'
	rd.Comment = '#'
	rd.TrimLeadingSpace = true
	for {
		rand, err := rd.Read()
		if err != nil {
			break
		}
		fmt.Printf("%q\n", rand)
	}
}

Rezultat

["cod" "produs" "pret"]
["101" "Cafea boabe 1kg" "89,90"]
["102" "Ceai verde" "14,50"]

Exemplul 3: Rând cu număr greșit de coloane

package main

import (
	"encoding/csv"
	"fmt"
	"strings"
)

func main() {
	rd := csv.NewReader(strings.NewReader("elev,nota\nAna,10\nRadu,9,absent\n"))
	for {
		rand, err := rd.Read()
		if err != nil {
			fmt.Println("Eroare:", err)
			if pe, ok := err.(*csv.ParseError); ok {
				fmt.Println("Rândul:", pe.Line)
			}
			break
		}
		fmt.Println(rand)
	}
}

Rezultat

[elev nota]
[Ana 10]
Eroare: record on line 3: wrong number of fields
Rândul: 3

Greșeli frecvente

  • Desparți singur rândurile cu strings.Split(linie, ","). Un câmp ca "Ionescu, Mihai" se rupe în două; folosește encoding/csv.
  • Uiți că primul rând este antetul și îl prelucrezi ca date (de exemplu strconv.Atoi("salariu") dă eroare). Citește-l separat înainte de buclă.
  • Fișierele salvate din Excel pot începe cu marcajul BOM (\ufeff), care se lipește de numele primei coloane. Elimină-l cu strings.TrimPrefix(antet[0], "\ufeff").

Comenzi înrudite

  • encoding/csv.Reader.ReadAll: Citește toate rândurile rămase dintr-un CSV deodată, ca [][]string; potrivit pentru fișiere mici.
  • encoding/csv.Writer: Scrie fișiere CSV: Write adaugă un rând (cu ghilimele unde e nevoie), Flush trimite datele din buffer la destinație.
  • encoding/csv.Writer.WriteAll: Scrie toate rândurile date deodată și apelează singur Flush; returnează eroarea, dacă apare.