os.ReadFile în Go

Citește tot conținutul unui fișier într-un slice de octeți, dintr-un singur apel.

Sintaxă
func ReadFile(name string) ([]byte, error)

Ce face os.ReadFile

os.ReadFile deschide fișierul, îl citește în întregime și îl închide. Este cel mai simplu mod de a citi un fișier mic sau mediu: un fișier de configurare, o listă de note, un CSV mic.

Rezultatul este un []byte. Pentru text îl transformi cu string(date). Dacă fișierul nu există sau nu ai drept de citire, primești o eroare de tip *fs.PathError, al cărei mesaj conține operația și numele fișierului.

Pentru fișiere foarte mari (sute de MB) sau când vrei să prelucrezi rând cu rând, folosește os.Open împreună cu bufio.Scanner, ca să nu încarci totul în memorie. Înainte de Go 1.16 funcția se numea ioutil.ReadFile.

Parametri

Parametru Descriere
name Calea fișierului, relativă la directorul curent sau absolută.

Ce returnează

Conținutul fișierului ca []byte și nil, sau o eroare. Un fișier citit complet NU dă eroarea io.EOF.

Exemple

Exemplul 1: Citirea unui fișier text

Mai întâi scriem fișierul, ca exemplul să aibă ce citi. string(date) transformă octeții în text.

package main

import (
    "fmt"
    "os"
)

func main() {
    // pregătim un fișier ca exemplul să aibă ce citi
    if err := os.WriteFile("note.txt", []byte("Ana 9\nMihai 7\nIoana 10\n"), 0o644); err != nil {
        fmt.Println("eroare:", err)
        return
    }

    date, err := os.ReadFile("note.txt")
    if err != nil {
        fmt.Println("eroare:", err)
        return
    }
    fmt.Printf("Am citit %d octeți:\n", len(date))
    fmt.Print(string(date))
}

Rezultat

Am citit 23 octeți:
Ana 9
Mihai 7
Ioana 10

Exemplul 2: Fișier care nu există

Eroarea spune ce operație a eșuat (open) și pentru ce fișier. Cu errors.Is și fs.ErrNotExist afli motivul exact.

package main

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

func main() {
    _, err := os.ReadFile("setari.json")
    if err != nil {
        fmt.Println("eroare:", err)
        if errors.Is(err, fs.ErrNotExist) {
            fmt.Println("Fișierul lipsește, folosim setările implicite.")
        }
    }
}

Rezultat

eroare: open setari.json: no such file or directory
Fișierul lipsește, folosim setările implicite.

Exemplul 3: Media notelor dintr-un fișier

Împărțim textul pe rânduri, apoi fiecare rând în nume și notă.

package main

import (
    "fmt"
    "os"
    "strconv"
    "strings"
)

func main() {
    os.WriteFile("note.txt", []byte("Ana 9\nMihai 7\nIoana 10\n"), 0o644)

    date, err := os.ReadFile("note.txt")
    if err != nil {
        fmt.Println("eroare:", err)
        return
    }
    suma, numar := 0, 0
    for _, rand := range strings.Split(strings.TrimSpace(string(date)), "\n") {
        campuri := strings.Fields(rand)
        nota, _ := strconv.Atoi(campuri[1])
        fmt.Printf("%-6s %2d\n", campuri[0], nota)
        suma += nota
        numar++
    }
    fmt.Printf("Media: %.2f\n", float64(suma)/float64(numar))
}

Rezultat

Ana     9
Mihai   7
Ioana  10
Media: 8.67

Greșeli frecvente

  • Ignori eroarea (date, _ := os.ReadFile(...)). Dacă fișierul lipsește, date este gol și programul continuă cu date greșite.
  • Citești cu os.ReadFile fișiere de mai mulți GB. Totul ajunge în memorie; pentru fișiere mari citește pe bucăți cu bufio.Scanner sau io.Copy.
  • Folosești o cale relativă și rulezi programul din alt director. Calea relativă pornește de la directorul curent al procesului, nu de la locul fișierului .go.

Comenzi înrudite

  • os.WriteFile: Scrie octeții dați într-un fișier: îl creează dacă lipsește și îi înlocuiește conținutul dacă există.
  • os.File: Tipul care reprezintă un fișier deschis; îl obții cu os.Open, os.Create sau os.OpenFile.
  • bufio.NewScanner: Creează un bufio.Scanner, cel mai simplu mod de a citi un text rând cu rând (sau cuvânt cu cuvânt).
  • io.ReadAll: Citește tot ce oferă un Reader, până la final, și returnează datele ca slice de octeți.
  • os.IsNotExist: IsNotExist spune dacă o eroare înseamnă „fișierul nu există”; IsExist, dacă înseamnă „există deja”.