Bibliothèque csv pour travailler avec les fichiers CSV en Rust
CSV (Comma-Separated Values) est l'un des formats les plus courants pour stocker des données tabulaires. En Rust, il existe une bibliothèque puissante, flexible et performante appelée csv, qui fait partie de l'écosystème BurntSushi (auteur de ripgrep et regex). Elle permet de lire, écrire, sérialiser et désérialiser des données avec un minimum d'effort et une sécurité de type maximale.
Installation
Ajoutez la dépendance dans Cargo.toml :
[dependencies]csv = "1.3"Pour la sérialisation/désérialisation des structures, vous aurez également besoin de serde :
[dependencies]csv = "1.3"serde = { version = "1.0", features = ["derive"] }Fonctionnalités principales de la bibliothèque
- Lecture et écriture avec des séparateurs, guillemets et caractères d'échappement personnalisables.
- Traitement automatique des en-têtes — travail par noms de colonnes.
- Sérialisation/Désérialisation via
serde— conversion des lignes CSV en structures Rust fortement typées. - Gestion flexible des erreurs — localisation des erreurs (numéro de ligne, colonne).
- Traitement par flux — travail avec de gros fichiers sans tout charger en mémoire.
- Prise en charge des encodages non UTF-8 (via des crates externes, par exemple
encoding).
Lecture d'un fichier CSV
La façon la plus simple de lire un CSV est d'utiliser Reader et un itérateur sur les enregistrements.
Exemple 1 : Lecture sans en-têtes
use csv::ReaderBuilder;use std::error::Error;
fn read_csv_no_headers() -> Result<(), Box<dyn Error>> { let data = "name,age,cityAlice,30,LondonBob,25,Paris"; let mut reader = ReaderBuilder::new() .has_headers(false) .from_reader(data.as_bytes());
for result in reader.records() { let record = result?; println!("{:?}", record); } Ok(())}Exemple 2 : Lecture avec en-têtes
use csv::Reader;use std::error::Error;
fn read_csv_with_headers() -> Result<(), Box<dyn Error>> { let data = "name,age,cityAlice,30,LondonBob,25,Paris"; let mut reader = Reader::from_reader(data.as_bytes());
for result in reader.deserialize() { let record: (String, u32, String) = result?; println!("{} is {} years old from {}", record.0, record.1, record.2); } Ok(())}Utilisation de Serde pour un typage strict
La manière la plus pratique est de définir une structure annotée avec #[derive(Deserialize)].
use serde::Deserialize;use csv::Reader;use std::error::Error;
#[derive(Debug, Deserialize)]struct Person { name: String, age: u32, city: String,}
fn read_typed_csv() -> Result<(), Box<dyn Error>> { let data = "name,age,cityAlice,30,LondonBob,25,Paris"; let mut reader = Reader::from_reader(data.as_bytes());
for result in reader.deserialize() { let person: Person = result?; println!("{:?}", person); } Ok(())}Cela garantit que les données seront automatiquement converties dans les types souhaités. Si, par exemple, le champ age contient la chaîne "abc", le programme retournera une erreur indiquant la ligne et la colonne.
Écriture d'un fichier CSV
Pour l'écriture, on utilise Writer. On peut écrire à la fois des chaînes brutes et des structures sérialisées.
Exemple : écriture via une structure
use serde::Serialize;use csv::Writer;use std::error::Error;
#[derive(Debug, Serialize)]struct Person { name: String, age: u32, city: String,}
fn write_csv() -> Result<(), Box<dyn