00
:
00
:
00
:
00
•Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Lavorare con i File in Go

Go offre strumenti potenti e semplici per lavorare con i file attraverso i pacchetti os, bufio, io e path/filepath. La gestione dei file in Go segue il principio della semplicita, con funzioni ad alto livello per le operazioni comuni e accesso a basso livello quando necessario.

Aprire un File con os.Open

os.Open apre un file in sola lettura:

package main

import (
    "fmt"
    "os"
)

func main() {
    file, err := os.Open("esempio.txt")
    if err != nil {
        fmt.Println("Errore:", err)
        return
    }
    defer file.Close() // IMPORTANTE: chiudere sempre il file

    fmt.Println("File aperto con successo")
}

Creare un File con os.Create

os.Create crea un nuovo file (o tronca un file esistente) in modalita scrittura:

func main() {
    file, err := os.Create("output.txt")
    if err != nil {
        fmt.Println("Errore:", err)
        return
    }
    defer file.Close()

    file.WriteString("Ciao, mondo!\n")
    file.WriteString("Scritto da Go.\n")
}

Leggere File

Lettura Completa con os.ReadFile

Il modo piu semplice per leggere un intero file in memoria:

package main

import (
    "fmt"
    "os"
)

func main() {
    contenuto, err := os.ReadFile("esempio.txt")
    if err != nil {
        fmt.Println("Errore:", err)
        return
    }

    fmt.Println(string(contenuto))
}

os.ReadFile restituisce un []byte con l’intero contenuto del file.

Lettura Riga per Riga con bufio.Scanner

Per file grandi, e meglio leggere riga per riga:

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    file, err := os.Open("esempio.txt")
    if err != nil {
        fmt.Println("Errore:", err)
        return
    }
    defer file.Close()

    scanner := bufio.NewScanner(file)
    numeroRiga := 1

    for scanner.Scan() {
        fmt.Printf("%d: %s\n", numeroRiga, scanner.Text())
        numeroRiga++
    }

    if err := scanner.Err(); err != nil {
        fmt.Println("Errore durante la lettura:", err)
    }
}

Lettura con bufio.Reader

Per un controllo piu fine sulla lettura:

func main() {
    file, err := os.Open("esempio.txt")
    if err != nil {
        fmt.Println("Errore:", err)
        return
    }
    defer file.Close()

    reader := bufio.NewReader(file)

    for {
        riga, err := reader.ReadString('\n')
        if err != nil {
            break
        }
        fmt.Print(riga)
    }
}

Scrivere File

Scrittura Completa con os.WriteFile

Il modo piu semplice per scrivere un file:

func main() {
    contenuto := []byte("Ciao, mondo!\nScritto con os.WriteFile.\n")

    err := os.WriteFile("output.txt", contenuto, 0644)
    if err != nil {
        fmt.Println("Errore:", err)
        return
    }

    fmt.Println("File scritto con successo")
}

Il terzo parametro (0644) definisce i permessi del file.

Scrittura con bufio.Writer

Per scritture bufferizzate e piu efficienti:

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    file, err := os.Create("output.txt")
    if err != nil {
        fmt.Println("Errore:", err)
        return
    }
    defer file.Close()

    writer := bufio.NewWriter(file)

    writer.WriteString("Prima riga\n")
    writer.WriteString("Seconda riga\n")
    writer.WriteString("Terza riga\n")

    // IMPORTANTE: svuotare il buffer per assicurarsi che i dati vengano scritti
    writer.Flush()
}

Aggiungere a un File Esistente

Per aggiungere contenuto senza sovrascrivere:

func main() {
    file, err := os.OpenFile("log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        fmt.Println("Errore:", err)
        return
    }
    defer file.Close()

    file.WriteString("Nuova riga di log\n")
}

I flag principali di os.OpenFile:

  • os.O_RDONLY: sola lettura
  • os.O_WRONLY: sola scrittura
  • os.O_RDWR: lettura e scrittura
  • os.O_APPEND: aggiunge alla fine
  • os.O_CREATE: crea il file se non esiste
  • os.O_TRUNC: tronca il file all’apertura

Permessi dei File

I permessi in Go seguono il sistema Unix (ottale):

// Permessi comuni
os.WriteFile("file.txt", dati, 0644) // rw-r--r-- (lettura per tutti, scrittura per il proprietario)
os.WriteFile("script.sh", dati, 0755) // rwxr-xr-x (eseguibile)
os.WriteFile("segreto.txt", dati, 0600) // rw------- (solo proprietario)
os.Mkdir("cartella", 0755)             // rwxr-xr-x

Defer per Chiudere i File

Usare defer per chiudere i file e una best practice fondamentale in Go:

func leggiFile(percorso string) (string, error) {
    file, err := os.Open(percorso)
    if err != nil {
        return "", err
    }
    defer file.Close() // garantisce la chiusura anche in caso di errore

    contenuto, err := io.ReadAll(file)
    if err != nil {
        return "", err
    }

    return string(contenuto), nil
}

Lavorare con le Directory

Creare Directory

// Crea una singola directory
err := os.Mkdir("nuova_cartella", 0755)

// Crea directory annidate (come mkdir -p)
err = os.MkdirAll("percorso/annidato/profondo", 0755)

Leggere il Contenuto di una Directory

func main() {
    entries, err := os.ReadDir(".")
    if err != nil {
        fmt.Println("Errore:", err)
        return
    }

    for _, entry := range entries {
        if entry.IsDir() {
            fmt.Printf("[DIR]  %s\n", entry.Name())
        } else {
            info, _ := entry.Info()
            fmt.Printf("[FILE] %s (%d bytes)\n", entry.Name(), info.Size())
        }
    }
}

Rimuovere File e Directory

// Rimuove un singolo file o directory vuota
os.Remove("file.txt")

// Rimuove ricorsivamente (come rm -rf)
os.RemoveAll("cartella_da_eliminare")

Il Pacchetto filepath

Il pacchetto path/filepath fornisce funzioni per manipolare i percorsi in modo portabile:

package main

import (
    "fmt"
    "path/filepath"
)

func main() {
    // Unire percorsi
    percorso := filepath.Join("home", "utente", "documenti", "file.txt")
    fmt.Println(percorso) // home/utente/documenti/file.txt

    // Ottenere la directory
    dir := filepath.Dir(percorso)
    fmt.Println(dir) // home/utente/documenti

    // Ottenere il nome del file
    nome := filepath.Base(percorso)
    fmt.Println(nome) // file.txt

    // Ottenere l'estensione
    ext := filepath.Ext(percorso)
    fmt.Println(ext) // .txt

    // Percorso assoluto
    abs, _ := filepath.Abs("file.txt")
    fmt.Println(abs)
}

Camminare in una Directory (Walk)

func main() {
    filepath.WalkDir(".", func(percorso string, d os.DirEntry, err error) error {
        if err != nil {
            return err
        }
        fmt.Println(percorso)
        return nil
    })
}

Conclusione

Go offre un set completo di strumenti per lavorare con i file, dalla lettura e scrittura semplice con os.ReadFile/os.WriteFile, alla gestione avanzata con bufio per operazioni bufferizzate. Usare defer per chiudere i file, gestire correttamente i permessi e sfruttare il pacchetto filepath per i percorsi sono pratiche essenziali per scrivere codice Go robusto e portabile.