Phase 5Projet pratique

#17 Entrées/sorties fichiers

std::fs, lire, écrire

Lire des fichiers

Rust offre plusieurs façons de lire des fichiers. La plus simple est std::fs::read_to_string, qui charge tout le fichier en mémoire d'un coup.

Lire un fichier entier
use std::fs;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Méthode simple : tout lire d'un coup
    let contenu = fs::read_to_string("hello.txt")?;
    println!("Contenu : {}", contenu);

    // Lire en octets bruts (pour fichiers binaires)
    let octets = fs::read("image.png")?;
    println!("Taille : {} octets", octets.len());

    Ok(())
}

Lire ligne par ligne

Pour les fichiers volumineux, mieux vaut lire ligne par ligne avec un BufReader qui utilise un tampon mémoire.

Lire ligne par ligne
use std::fs::File;
use std::io::{self, BufRead, BufReader};

fn main() -> io::Result<()> {
    let fichier = File::open("donnees.txt")?;
    let lecteur = BufReader::new(fichier);

    for (numero, ligne) in lecteur.lines().enumerate() {
        let ligne = ligne?;
        println!("Ligne {} : {}", numero + 1, ligne);
    }

    Ok(())
}

Écrire des fichiers

L'écriture est tout aussi simple. fs::write crée le fichier ou le remplace s'il existe déjà.

Écrire dans un fichier
use std::fs;
use std::io::Write;

fn main() -> std::io::Result<()> {
    // Méthode simple : écrire tout d'un coup
    fs::write("sortie.txt", "Bonjour depuis Rust !")?;
    println!("Fichier écrit avec succès !");

    // Avec plus de contrôle via File
    let mut fichier = fs::File::create("rapport.txt")?;
    writeln!(fichier, "=== Rapport ===")?;
    writeln!(fichier, "Date : 2026-03-04")?;
    writeln!(fichier, "Statut : OK")?;

    Ok(())
}

Ajouter à un fichier

Pour ajouter du contenu à la fin d'un fichier existant (sans l'écraser), on utilise OpenOptions avec l'option append.

Ajouter à un fichier
use std::fs::OpenOptions;
use std::io::Write;

fn main() -> std::io::Result<()> {
    let mut fichier = OpenOptions::new()
        .create(true)   // créer si absent
        .append(true)   // ajouter à la fin
        .open("journal.log")?;

    writeln!(fichier, "[INFO] Application démarrée")?;
    writeln!(fichier, "[INFO] Connexion réussie")?;
    println!("Ligne ajoutée au journal.");

    Ok(())
}

Travailler avec les chemins

Le module std::path fournit Path et PathBuf pour manipuler les chemins de fichiers de manière portable (Windows, Linux, macOS).

Manipuler les chemins
use std::path::{Path, PathBuf};

fn main() {
    // Créer un chemin
    let chemin = Path::new("data/output.txt");

    // Obtenir des informations
    println!("Nom du fichier : {:?}", chemin.file_name());
    println!("Extension : {:?}", chemin.extension());
    println!("Dossier parent : {:?}", chemin.parent());

    // Construire un chemin avec PathBuf
    let mut chemin_complet = PathBuf::from("/home/user");
    chemin_complet.push("file-io-demo");
    chemin_complet.push("data");
    chemin_complet.push("output.txt");
    println!("Chemin absolu : {}", chemin_complet.display());

    // Vérifier si un chemin existe
    let existe = chemin_complet.exists();
    println!("Le fichier existe : {}", existe);

    // Joindre des chemins
    let base = Path::new("/home/user");
    let complet = base.join("projets").join("demo.rs");
    println!("Chemin joint : {}", complet.display());
}

Gestion des erreurs I/O

Les opérations de fichiers peuvent échouer pour de nombreuses raisons. Le type std::io::Error fournit un kind() pour identifier la nature de l'erreur.

Gestion des erreurs I/O
use std::fs;
use std::io::{self, ErrorKind};

fn lire_ou_creer(chemin: &str) -> io::Result<String> {
    match fs::read_to_string(chemin) {
        Ok(contenu) => Ok(contenu),
        Err(e) => match e.kind() {
            ErrorKind::NotFound => {
                // Le fichier n'existe pas : on le crée
                let defaut = String::from("contenu par défaut");
                fs::write(chemin, &defaut)?;
                Ok(defaut)
            }
            ErrorKind::PermissionDenied => {
                Err(io::Error::new(
                    ErrorKind::PermissionDenied,
                    format!("Permission refusée pour {}", chemin),
                ))
            }
            _ => Err(e), // Propager les autres erreurs
        },
    }
}

fn main() {
    match lire_ou_creer("config.txt") {
        Ok(contenu) => println!("Contenu : {}", contenu),
        Err(e) => eprintln!("Erreur : {} (type : {:?})", e, e.kind()),
    }
}

À vous de jouer

Essayez les commandes ci-dessous pour compiler et exécuter le programme :

terminal — cargo
user@stemlegacy:~/file-io-demo$