Ce face io.Reader
io.Reader este una dintre cele mai importante interfețe din Go. Orice tip care are metoda Read(p []byte) (n int, err error) este un Reader: *os.File, strings.Reader, bytes.Buffer, bufio.Reader, corpul unui răspuns HTTP, o conexiune de rețea.
Regulile metodei: pune până la len(p) octeți în p, returnează câți a pus în n; la sfârșitul datelor returnează io.EOF. Poate returna n > 0 și o eroare în același apel; prelucrează întâi cei n octeți, apoi eroarea.
Avantajul: o funcție care primește un io.Reader merge cu orice sursă. Scrii o dată funcția și o testezi cu strings.NewReader, apoi o folosești cu fișiere sau rețea.
Parametri
| Parametru | Descriere |
|---|---|
p |
Buffer-ul în care sursa pune datele. |
Ce returnează
Numărul de octeți citiți și o eroare (io.EOF la final).
Exemple
Exemplul 1: O funcție, mai multe surse
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"strings"
)
func numaraCuvinte(r io.Reader) int {
s := bufio.NewScanner(r)
s.Split(bufio.ScanWords)
n := 0
for s.Scan() {
n++
}
return n
}
func main() {
fmt.Println("text:", numaraCuvinte(strings.NewReader("Ana are mere și pere")))
fmt.Println("buffer:", numaraCuvinte(bytes.NewBufferString("unu doi trei")))
os.WriteFile("poveste.txt", []byte("A fost odată ca niciodată"), 0o644)
f, _ := os.Open("poveste.txt")
defer f.Close()
fmt.Println("fișier:", numaraCuvinte(f))
}
Rezultat
text: 5
buffer: 3
fișier: 5
Exemplul 2: Un Reader scris de mână
Tipul nostru produce litera a de n ori. Orice funcție care primește io.Reader îl poate folosi.
package main
import (
"fmt"
"io"
)
type repetitor struct {
ramase int
}
func (r *repetitor) Read(p []byte) (int, error) {
if r.ramase == 0 {
return 0, io.EOF
}
n := min(len(p), r.ramase)
for i := range n {
p[i] = 'a'
}
r.ramase -= n
return n, nil
}
func main() {
date, _ := io.ReadAll(&repetitor{ramase: 12})
fmt.Println(string(date), len(date))
}
Rezultat
aaaaaaaaaaaa 12
Exemplul 3: Combinarea Reader-elor
io.MultiReader citește surse una după alta, iar io.LimitReader se oprește după un număr de octeți.
package main
import (
"fmt"
"io"
"strings"
)
func main() {
antet := strings.NewReader("Nume,Oraș\n")
date := strings.NewReader("Ana,Iași\nMihai,Cluj\n")
tot, _ := io.ReadAll(io.MultiReader(antet, date))
fmt.Print(string(tot))
primii, _ := io.ReadAll(io.LimitReader(strings.NewReader("abcdefghij"), 4))
fmt.Println(string(primii))
}
Rezultat
Nume,Oraș
Ana,Iași
Mihai,Cluj
abcd
Greșeli frecvente
- Ignori octeții primiți împreună cu o eroare. Un
Readpoate returna date șiio.EOFîn același apel. - Scrii funcții care primesc
*os.Filecând au nevoie doar să citească. Primeșteio.Reader: funcția devine mai ușor de testat și de refolosit.
Comenzi înrudite
io.Writer: Interfața pentru orice destinație în care se pot scrie octeți: fișiere, ecran, buffer-e, răspunsuri HTTP.io.ReadAll: Citește tot ce oferă un Reader, până la final, și returnează datele ca slice de octeți.io.Copy: Copiază toate datele dintr-un Reader într-un Writer, pe bucăți, fără să le țină pe toate în memorie.os.File.Read: Citește din fișier cel mult len(b) octeți în slice-ul b și returnează câți a citit.bufio.NewReader: Învelește un io.Reader într-un bufio.Reader, care citește pe blocuri și oferă ReadString, ReadRune, ReadLine.io.ReadWriter: Interfața pentru tipurile din care se poate și citi, și în care se poate scrie (Reader + Writer).io.MultiReader: Leagă mai multe Reader-e unul după altul, ca și cum ar fi o singură sursă continuă.io.LimitReader: Învelește un Reader astfel încât să poată fi citiți din el cel mult n octeți; după aceea dă io.EOF.