io.Writer în Go

Interfața pentru orice destinație în care se pot scrie octeți: fișiere, ecran, buffer-e, răspunsuri HTTP.

Sintaxă
type Writer interface {
    Write(p []byte) (n int, err error)
}

Ce face io.Writer

io.Writer este perechea lui io.Reader. Orice tip cu metoda Write(p []byte) (n int, err error) este un Writer: os.Stdout, *os.File, bytes.Buffer, strings.Builder, bufio.Writer, http.ResponseWriter, un hash.Hash.

Regula metodei: scrie tot p; dacă scrie mai puțin (n < len(p)), trebuie să returneze o eroare. Funcțiile fmt.Fprintf, fmt.Fprintln, io.Copy, io.WriteString și json.NewEncoder primesc un io.Writer, deci pot scrie oriunde.

Parametri

Parametru Descriere
p Octeții de scris.

Ce returnează

Numărul de octeți scriși și nil, sau o eroare.

Exemple

Exemplul 1: Aceeași funcție scrie pe ecran sau în memorie

package main

import (
    "fmt"
    "io"
    "os"
    "strings"
)

func scrieFactura(w io.Writer, client string, total float64) {
    fmt.Fprintf(w, "Client: %s\n", client)
    fmt.Fprintf(w, "Total:  %.2f lei\n", total)
}

func main() {
    scrieFactura(os.Stdout, "Ana Popescu", 249.9)

    var sb strings.Builder
    scrieFactura(&sb, "Mihai Ionescu", 80)
    fmt.Printf("în memorie: %q\n", sb.String())
}

Rezultat

Client: Ana Popescu
Total:  249.90 lei
în memorie: "Client: Mihai Ionescu\nTotal:  80.00 lei\n"

Exemplul 2: Scriere în mai multe locuri deodată

io.MultiWriter trimite aceleași date la toți Writer-ii dați.

package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    f, _ := os.Create("jurnal.txt")
    defer f.Close()

    w := io.MultiWriter(os.Stdout, f)
    fmt.Fprintln(w, "comanda 1042 a fost livrată")

    date, _ := os.ReadFile("jurnal.txt")
    fmt.Printf("în fișier: %q\n", date)
}

Rezultat

comanda 1042 a fost livrată
în fișier: "comanda 1042 a fost livrată\n"

Exemplul 3: Un Writer care numără octeții

package main

import (
    "fmt"
    "io"
    "strings"
)

type numarator struct {
    total int
}

func (n *numarator) Write(p []byte) (int, error) {
    n.total += len(p)
    return len(p), nil
}

func main() {
    var n numarator
    io.Copy(&n, strings.NewReader("Bună ziua din Brașov!"))
    fmt.Fprintf(&n, " și din %s", "Sibiu")
    fmt.Println("octeți:", n.total)
}

Rezultat

octeți: 37

Greșeli frecvente

  • Implementezi Write și returnezi 0, nil sau mai puțin decât len(p) fără eroare. Funcțiile ca io.Copy raportează atunci io.ErrShortWrite.
  • Păstrezi slice-ul p primit în Write pentru mai târziu. Apelantul îl poate refolosi; copiază datele dacă ai nevoie de ele.

Comenzi înrudite

  • io.Reader: Interfața pentru orice sursă de date din care se poate citi: fișiere, text, conexiuni, răspunsuri HTTP.
  • io.WriteString: Scrie un text în orice io.Writer, folosind metoda WriteString a acestuia dacă există.
  • 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.Write: Scrie octeți (Write) sau text (WriteString) în fișier, la poziția curentă.
  • bufio.NewWriter: Învelește un io.Writer într-un bufio.Writer, care strânge scrierile mici într-un buffer și le trimite în blocuri.
  • io.MultiWriter: Creează un Writer care trimite fiecare scriere la toți Writer-ii dați, ca tee din Unix.