io.CopyN în Go

Copiază exact n octeți dintr-un Reader într-un Writer (sau mai puțini, cu eroare, dacă sursa se termină).

Sintaxă
func CopyN(dst Writer, src Reader, n int64) (written int64, err error)

Ce face io.CopyN

io.CopyN copiază primii n octeți din src. Dacă sursa are mai puțini, copiază ce există și returnează io.EOF, ca să știi că lipsesc date.

Este utilă pentru formate cu lungime cunoscută: un antet de n octeți, o porțiune dintr-un fișier, primele n octeți dintr-o încărcare. Pentru a limita cât citești dintr-o sursă nesigură poți folosi și io.LimitReader.

Parametri

Parametru Descriere
dst Destinația.
src Sursa.
n Numărul de octeți de copiat.

Ce returnează

Octeții copiați și nil dacă au fost exact n; altfel o eroare (io.EOF dacă sursa s-a terminat mai devreme).

Exemple

Exemplul 1: Primii octeți dintr-un text

package main

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

func main() {
    src := strings.NewReader("Universitatea din Iași")
    n, err := io.CopyN(os.Stdout, src, 13)
    fmt.Println()
    fmt.Println("copiați:", n, "eroare:", err)

    rest, _ := io.ReadAll(src)
    fmt.Printf("au rămas: %q\n", rest)
}

Rezultat

Universitatea
copiați: 13 eroare: <nil>
au rămas: " din Iași"

Exemplul 2: Sursa prea scurtă

package main

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

func main() {
    var sb strings.Builder
    n, err := io.CopyN(&sb, strings.NewReader("abc"), 10)
    fmt.Printf("copiați: %d, text: %q, eroare: %v\n", n, sb.String(), err)
}

Rezultat

copiați: 3, text: "abc", eroare: EOF

Exemplul 3: Împărțirea unui fișier în bucăți

package main

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

func main() {
    os.WriteFile("mare.txt", []byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0o644)
    in, _ := os.Open("mare.txt")
    defer in.Close()

    for parte := 1; ; parte++ {
        nume := fmt.Sprintf("parte%d.txt", parte)
        out, _ := os.Create(nume)
        n, err := io.CopyN(out, in, 16)
        out.Close()
        if n > 0 {
            date, _ := os.ReadFile(nume)
            fmt.Printf("%s: %s\n", nume, date)
        } else {
            os.Remove(nume)
        }
        if errors.Is(err, io.EOF) {
            break
        }
    }
}

Rezultat

parte1.txt: 0123456789ABCDEF
parte2.txt: GHIJKLMNOPQRSTUV
parte3.txt: WXYZ

Greșeli frecvente

  • Ignori io.EOF de la CopyN. Aici înseamnă că sursa a avut mai puțin de n octeți, ceea ce poate fi o eroare de format.

Comenzi înrudite

  • io.Copy: Copiază toate datele dintr-un Reader într-un Writer, pe bucăți, fără să le țină pe toate în memorie.
  • io.ReadFull: ReadFull umple complet buffer-ul din Reader; ReadAtLeast citește cel puțin min octeți.
  • io.Reader: Interfața pentru orice sursă de date din care se poate citi: fișiere, text, conexiuni, răspunsuri HTTP.