#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.
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.
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à.
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.
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).
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.
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 :