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

Lavorare con i File

Rust offre un modulo std::fs completo per lavorare con il file system. Le operazioni sui file sono sicure grazie al sistema dei tipi e alla gestione esplicita degli errori con Result.

Aprire un File con File::open

File::open apre un file in sola lettura:

use std::fs::File;
use std::io::Read;

fn main() -> std::io::Result<()> {
    let mut file = File::open("esempio.txt")?;

    let mut contenuto = String::new();
    file.read_to_string(&mut contenuto)?;

    println!("Contenuto:\n{}", contenuto);
    Ok(())
}

Creare un File con File::create

File::create crea un nuovo file o sovrascrive quello esistente:

use std::fs::File;
use std::io::Write;

fn main() -> std::io::Result<()> {
    let mut file = File::create("output.txt")?;

    file.write_all(b"Prima riga\n")?;
    file.write_all(b"Seconda riga\n")?;
    writeln!(file, "Terza riga con numero: {}", 42)?;

    println!("File creato con successo!");
    Ok(())
}

Lettura Rapida con fs::read_to_string

Per leggere un intero file in una stringa, la funzione piu comoda è fs::read_to_string:

use std::fs;

fn main() -> std::io::Result<()> {
    let contenuto = fs::read_to_string("config.txt")?;
    println!("{}", contenuto);

    // Per leggere come byte
    let bytes = fs::read("immagine.png")?;
    println!("Dimensione: {} byte", bytes.len());

    Ok(())
}

Lettura Bufferizzata con BufReader

Per file grandi, BufReader è piu efficiente perché legge a blocchi:

use std::fs::File;
use std::io::{BufRead, BufReader};

fn main() -> std::io::Result<()> {
    let file = File::open("log.txt")?;
    let reader = BufReader::new(file);

    for (numero, riga) in reader.lines().enumerate() {
        let riga = riga?;
        println!("{:4}: {}", numero + 1, riga);
    }

    Ok(())
}

Scrittura Bufferizzata con BufWriter

BufWriter accumula le scritture in un buffer prima di inviarle al disco:

use std::fs::File;
use std::io::{BufWriter, Write};

fn main() -> std::io::Result<()> {
    let file = File::create("dati.csv")?;
    let mut writer = BufWriter::new(file);

    writeln!(writer, "nome,eta,citta")?;
    writeln!(writer, "Mario,30,Roma")?;
    writeln!(writer, "Giulia,25,Milano")?;
    writeln!(writer, "Luca,35,Napoli")?;

    writer.flush()?;
    println!("CSV scritto con successo!");
    Ok(())
}

Append su File Esistente

Per aggiungere contenuto senza sovrascrivere, si usa OpenOptions:

use std::fs::OpenOptions;
use std::io::Write;

fn main() -> std::io::Result<()> {
    let mut file = OpenOptions::new()
        .append(true)
        .create(true) // crea il file se non esiste
        .open("log.txt")?;

    writeln!(file, "Nuova voce di log: operazione completata")?;

    Ok(())
}

Scrittura Rapida con fs::write

Per scrivere rapidamente un contenuto in un file:

use std::fs;

fn main() -> std::io::Result<()> {
    // Scrive una stringa
    fs::write("nota.txt", "Contenuto della nota")?;

    // Scrive dei byte
    fs::write("dati.bin", &[0u8, 1, 2, 3, 4])?;

    Ok(())
}

Metadati dei File

Si possono ottenere informazioni su un file tramite i metadati:

use std::fs;

fn main() -> std::io::Result<()> {
    let metadata = fs::metadata("esempio.txt")?;

    println!("Tipo: {}", if metadata.is_file() { "file" } else { "directory" });
    println!("Dimensione: {} byte", metadata.len());
    println!("Sola lettura: {}", metadata.permissions().readonly());

    if let Ok(modificato) = metadata.modified() {
        println!("Ultima modifica: {:?}", modificato);
    }

    Ok(())
}

Creare e Rimuovere Directory

Il modulo fs offre funzioni per gestire le directory:

use std::fs;

fn main() -> std::io::Result<()> {
    // Crea una singola directory
    fs::create_dir("nuova_cartella")?;

    // Crea directory annidate (come mkdir -p)
    fs::create_dir_all("progetto/src/moduli")?;

    // Elenca il contenuto di una directory
    for entry in fs::read_dir(".")? {
        let entry = entry?;
        let tipo = if entry.file_type()?.is_dir() { "DIR" } else { "FILE" };
        println!("[{}] {}", tipo, entry.file_name().to_string_lossy());
    }

    // Rimuovi una directory vuota
    fs::remove_dir("nuova_cartella")?;

    // Rimuovi una directory e tutto il suo contenuto
    fs::remove_dir_all("progetto")?;

    Ok(())
}

Altre Operazioni su File

use std::fs;

fn main() -> std::io::Result<()> {
    // Copiare un file
    fs::copy("originale.txt", "copia.txt")?;

    // Rinominare o spostare un file
    fs::rename("vecchio_nome.txt", "nuovo_nome.txt")?;

    // Eliminare un file
    fs::remove_file("da_eliminare.txt")?;

    Ok(())
}

Path e PathBuf

Path e PathBuf gestiscono i percorsi in modo cross-platform:

use std::path::{Path, PathBuf};

fn main() {
    // Path è un riferimento (come &str)
    let percorso = Path::new("/home/utente/documenti/file.txt");

    println!("Nome file: {:?}", percorso.file_name());
    println!("Estensione: {:?}", percorso.extension());
    println!("Directory padre: {:?}", percorso.parent());
    println!("Esiste: {}", percorso.exists());
    println!("È assoluto: {}", percorso.is_absolute());

    // PathBuf è posseduto (come String)
    let mut percorso_buf = PathBuf::from("/home/utente");
    percorso_buf.push("progetti");
    percorso_buf.push("rust");
    percorso_buf.set_extension("rs");

    println!("Percorso costruito: {}", percorso_buf.display());

    // Iterare sulle componenti del percorso
    for componente in percorso.components() {
        println!("  {:?}", componente);
    }

    // Unire percorsi con join
    let base = Path::new("/var/log");
    let completo = base.join("app").join("errori.log");
    println!("Percorso completo: {}", completo.display());
}

Esempio Completo: Elaborazione di File

use std::fs;
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::path::Path;

fn conta_righe(percorso: &Path) -> std::io::Result<usize> {
    let file = fs::File::open(percorso)?;
    let reader = BufReader::new(file);
    Ok(reader.lines().count())
}

fn main() -> std::io::Result<()> {
    let cartella = Path::new(".");

    for entry in fs::read_dir(cartella)? {
        let entry = entry?;
        let percorso = entry.path();

        if percorso.extension().map_or(false, |e| e == "txt") {
            let righe = conta_righe(&percorso)?;
            println!("{}: {} righe", percorso.display(), righe);
        }
    }

    Ok(())
}

Conclusione

Il modulo std::fs di Rust offre un’interfaccia completa per lavorare con file e directory. File::open e File::create gestiscono l’apertura e la creazione, BufReader e BufWriter ottimizzano le prestazioni, e Path/PathBuf garantiscono la gestione cross-platform dei percorsi. Grazie al tipo Result, ogni operazione rende esplicito il possibile fallimento, portando a codice robusto e affidabile.