os.OpenFile în Go

Deschide un fișier cu opțiuni alese de tine: citire, scriere, adăugare la final, creare, golire, creare exclusivă.

Sintaxă
func OpenFile(name string, flag int, perm FileMode) (*File, error)

Ce face os.OpenFile

os.OpenFile este funcția generală de deschidere; os.Open și os.Create o apelează cu opțiuni fixe. Al doilea argument combină cu | exact un mod de acces și oricâte opțiuni:

Mod de acces: os.O_RDONLY (doar citire), os.O_WRONLY (doar scriere), os.O_RDWR (ambele). Opțiuni: os.O_CREATE (creează dacă lipsește), os.O_APPEND (fiecare scriere merge la final), os.O_TRUNC (golește la deschidere), os.O_EXCL (împreună cu O_CREATE: eroare dacă fișierul există deja), os.O_SYNC (scriere sincronă pe disc).

perm contează doar când fișierul este creat (de exemplu 0o644, sau 0o600 pentru fișiere private) și se aplică după masca umask. Combinația cea mai des folosită este cea pentru jurnale: os.O_APPEND|os.O_CREATE|os.O_WRONLY.

Parametri

Parametru Descriere
name Calea fișierului.
flag Modul de acces și opțiunile, combinate cu |.
perm Drepturile pentru un fișier nou.

Ce returnează

Fișierul deschis și nil, sau nil și o eroare *fs.PathError.

Exemple

Exemplul 1: Jurnal cu adăugare la final

package main

import (
    "fmt"
    "os"
)

func scrieJurnal(mesaj string) error {
    f, err := os.OpenFile("magazin.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
    if err != nil {
        return err
    }
    defer f.Close()
    _, err = fmt.Fprintln(f, mesaj)
    return err
}

func main() {
    scrieJurnal("09:00 deschis")
    scrieJurnal("09:12 comanda 1042")
    scrieJurnal("09:40 comanda 1043")

    date, _ := os.ReadFile("magazin.log")
    fmt.Print(string(date))
}

Rezultat

09:00 deschis
09:12 comanda 1042
09:40 comanda 1043

Exemplul 2: Creare exclusivă cu O_EXCL

A doua încercare eșuează, pentru că fișierul există deja. Așa creezi sigur un fișier de blocare sau eviți suprascrierea.

package main

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

func main() {
    for i := 1; i <= 2; i++ {
        f, err := os.OpenFile("factura-1042.pdf", os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o644)
        if errors.Is(err, fs.ErrExist) {
            fmt.Println("încercarea", i, ": factura există deja, nu o suprascriu")
            continue
        }
        fmt.Println("încercarea", i, ": factură creată")
        f.Close()
    }
}

Rezultat

încercarea 1 : factură creată
încercarea 2 : factura există deja, nu o suprascriu

Exemplul 3: Citire și modificare în același fișier

package main

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

func main() {
    os.WriteFile("contor.txt", []byte("41"), 0o644)

    f, err := os.OpenFile("contor.txt", os.O_RDWR, 0)
    if err != nil {
        fmt.Println("eroare:", err)
        return
    }
    defer f.Close()

    date, _ := io.ReadAll(f)
    n, _ := strconv.Atoi(strings.TrimSpace(string(date)))
    f.Truncate(0)
    f.Seek(0, io.SeekStart)
    f.WriteString(strconv.Itoa(n + 1))

    nou, _ := os.ReadFile("contor.txt")
    fmt.Println("vizitatori:", string(nou))
}

Rezultat

vizitatori: 42

Greșeli frecvente

  • Uiți modul de acces: os.OpenFile(n, os.O_APPEND|os.O_CREATE, 0o644) deschide doar pentru citire (O_RDONLY este 0), iar scrierea dă eroare. Adaugă os.O_WRONLY.
  • Pui O_CREATE fără O_TRUNC și scrii un text mai scurt peste unul mai lung. Rămâne la final o bucată din conținutul vechi.
  • Dai perm în zecimal (644). Scrie 0o644.

Comenzi înrudite

  • os.Open: Deschide un fișier existent doar pentru citire și returnează un *os.File.
  • os.Create: Creează un fișier nou (sau golește unul existent) și îl deschide pentru scriere și citire.
  • os.File: Tipul care reprezintă un fișier deschis; îl obții cu os.Open, os.Create sau os.OpenFile.
  • os.IsNotExist: IsNotExist spune dacă o eroare înseamnă „fișierul nu există”; IsExist, dacă înseamnă „există deja”.
  • os.Truncate: Schimbă dimensiunea unui fișier: taie ce depășește sau completează cu octeți zero.