os.File.Read în Go

Citește din fișier cel mult len(b) octeți în slice-ul b și returnează câți a citit.

Sintaxă
func (f *File) Read(b []byte) (n int, err error)

Ce face os.File.Read

Read umple slice-ul b cu octeți de la poziția curentă din fișier și mută poziția mai departe. Returnează n, numărul de octeți citiți, care poate fi mai mic decât len(b). Folosește mereu doar b[:n].

La sfârșitul fișierului, Read returnează 0, io.EOF. io.EOF nu este o eroare reală, ci semnalul că nu mai sunt date. Este metoda interfeței io.Reader.

Rar apelezi Read direct; de obicei folosești io.ReadAll, io.ReadFull, io.Copy sau bufio.Scanner, care o apelează în buclă pentru tine.

Parametri

Parametru Descriere
b Buffer-ul în care se pun octeții; dimensiunea lui este numărul maxim citit într-un apel.

Ce returnează

Numărul de octeți citiți și nil, sau 0 și io.EOF la final, sau o eroare.

Exemple

Exemplul 1: Citire pe bucăți de 8 octeți

package main

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

func main() {
    os.WriteFile("mesaj.txt", []byte("Bun venit pe dexblog!"), 0o644)
    f, err := os.Open("mesaj.txt")
    if err != nil {
        fmt.Println("eroare:", err)
        return
    }
    defer f.Close()

    buf := make([]byte, 8)
    for {
        n, err := f.Read(buf)
        if n > 0 {
            fmt.Printf("%d octeți: %q\n", n, buf[:n])
        }
        if errors.Is(err, io.EOF) {
            fmt.Println("gata (io.EOF)")
            break
        }
        if err != nil {
            fmt.Println("eroare:", err)
            break
        }
    }
}

Rezultat

8 octeți: "Bun veni"
8 octeți: "t pe dex"
5 octeți: "blog!"
gata (io.EOF)

Exemplul 2: Semnătura unui fișier (primii octeți)

Fișierele PNG încep mereu cu aceiași 8 octeți. io.ReadFull garantează că i-am citit pe toți.

package main

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

func main() {
    os.WriteFile("poza.png", []byte("\x89PNG\r\n\x1a\nrestul imaginii"), 0o644)
    f, _ := os.Open("poza.png")
    defer f.Close()

    antet := make([]byte, 8)
    if _, err := io.ReadFull(f, antet); err != nil {
        fmt.Println("eroare:", err)
        return
    }
    fmt.Printf("% x\n", antet)
    fmt.Println("este PNG:", bytes.Equal(antet, []byte("\x89PNG\r\n\x1a\n")))
}

Rezultat

89 50 4e 47 0d 0a 1a 0a
este PNG: true

Greșeli frecvente

  • Folosești tot buf în loc de buf[:n]. La ultima citire, partea de după n conține date vechi.
  • Tratezi io.EOF ca pe o eroare și afișezi „eroare”. Este finalul normal al datelor.
  • Presupui că un singur Read umple buffer-ul. Poate citi mai puțin; folosește io.ReadFull când ai nevoie de exact len(b) octeți.

Comenzi înrudite

  • io.Reader: Interfața pentru orice sursă de date din care se poate citi: fișiere, text, conexiuni, răspunsuri HTTP.
  • io.ReadFull: ReadFull umple complet buffer-ul din Reader; ReadAtLeast citește cel puțin min octeți.
  • io.ReadAll: Citește tot ce oferă un Reader, până la final, și returnează datele ca slice de octeți.
  • os.File.Seek: Mută poziția curentă de citire/scriere din fișier, față de început, de poziția curentă sau de final.
  • bufio.NewReader: Învelește un io.Reader într-un bufio.Reader, care citește pe blocuri și oferă ReadString, ReadRune, ReadLine.