io.NewSectionReader în Go

Creează un Reader care vede doar o porțiune (de la off, n octeți) dintr-o sursă cu acces direct, ca un fișier.

Sintaxă
func NewSectionReader(r ReaderAt, off int64, n int64) *SectionReader

Ce face io.NewSectionReader

io.NewSectionReader primește o sursă care permite citirea de la orice poziție (io.ReaderAt: *os.File, *bytes.Reader, *strings.Reader) și returnează un *io.SectionReader limitat la octeții [off, off+n). Pentru el, poziția 0 este off, iar după n octeți vine io.EOF.

SectionReader implementează Read, Seek, ReadAt și Size. Pentru că folosește ReadAt, nu mută poziția sursei, deci poți avea mai multe secțiuni din același fișier citite în paralel. Este folosit la formate cu porțiuni la poziții cunoscute (arhive, imagini) și la descărcarea pe bucăți.

Parametri

Parametru Descriere
r Sursa cu acces direct (io.ReaderAt).
off Poziția de început a secțiunii.
n Lungimea secțiunii, în octeți.

Ce returnează

Un *io.SectionReader.

Exemple

Exemplul 1: O porțiune dintr-un text

package main

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

func main() {
    sursa := strings.NewReader("COD:RO123 NUME:Ana Popescu ORAS:Iasi")
    nume := io.NewSectionReader(sursa, 15, 11)
    date, _ := io.ReadAll(nume)
    fmt.Printf("%q, dimensiune secțiune: %d\n", date, nume.Size())

    oras := io.NewSectionReader(sursa, 32, 100) // cere mai mult decât există
    date, _ = io.ReadAll(oras)
    fmt.Printf("%q\n", date)
}

Rezultat

"Ana Popescu", dimensiune secțiune: 11
"Iasi"

Exemplul 2: Un fișier împărțit în bucăți citite în paralel

package main

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

func main() {
    os.WriteFile("date.bin", []byte("AAAABBBBCCCCDD"), 0o644)
    f, _ := os.Open("date.bin")
    defer f.Close()
    info, _ := f.Stat()

    const bucata = 4
    var wg sync.WaitGroup
    parti := make([]string, (info.Size()+bucata-1)/bucata)
    for i := range parti {
        wg.Go(func() {
            s := io.NewSectionReader(f, int64(i)*bucata, bucata)
            date, _ := io.ReadAll(s)
            parti[i] = string(date)
        })
    }
    wg.Wait()
    fmt.Println(parti)
}

Rezultat

[AAAA BBBB CCCC DD]

Greșeli frecvente

  • Încerci să folosești un io.Reader obișnuit (de exemplu corpul unei cereri HTTP). SectionReader are nevoie de ReadAt, adică de acces la orice poziție.

Comenzi înrudite

  • 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.
  • os.File.Seek: Mută poziția curentă de citire/scriere din fișier, față de început, de poziția curentă sau de final.
  • io.NewOffsetWriter: Creează un Writer care scrie într-o destinație cu acces direct (ca un fișier) începând de la poziția off.
  • io.Reader: Interfața pentru orice sursă de date din care se poate citi: fișiere, text, conexiuni, răspunsuri HTTP.