Trabajo con CSV en Rust: biblioteca csv y ejemplos prácticos
El formato CSV (Comma-Separated Values) sigue siendo una de las formas más populares de almacenar datos tabulares. En Rust, para trabajar con CSV existe una biblioteca madura y de alto rendimiento llamada csv, que proporciona una API conveniente para leer, escribir y procesar datos. En este artículo, analizaremos en detalle cómo trabajar eficientemente con CSV en Rust.
Instalación y configuración de la biblioteca
Para comenzar, agregue la dependencia al archivo Cargo.toml:
[dependencies]csv = "1.3"La biblioteca csv admite trabajo con codificaciones, delimitadores y comillas personalizables, y también proporciona la capacidad de serialización/deserialización de datos a través de los traits de serde.
Lectura de un archivo CSV
La forma más sencilla de leer un CSV es usar csv::Reader. Veamos un ejemplo con el archivo users.csv:
use std::error::Error;use csv::ReaderBuilder;
fn main() -> Result<(), Box<dyn Error>> { // Creamos un lector con configuración let mut rdr = ReaderBuilder::new() .has_headers(true) // primera línea son encabezados .delimiter(b',') // delimitador es la coma .from_path("users.csv")?;
// Mostramos los encabezados let headers = rdr.headers()?; println!("Headers: {:?}", headers);
// Iteramos sobre los registros for result in rdr.records() { let record = result?; println!("{:?}", record); } Ok(())}Procesamiento de registros mediante deserialización
Para trabajar con datos estructurados, es conveniente usar la deserialización en estructuras personalizadas. Agregue serde y serde_derive:
[dependencies]csv = "1.3"serde = { version = "1.0", features = ["derive"] }Ahora puede definir una estructura y leer los datos directamente:
use serde::Deserialize;
#[derive(Debug, Deserialize)]struct User { name: String, age: u8, email: String,}
fn main() -> Result<(), Box<dyn std::error::Error>> { let mut rdr = csv::Reader::from_path("users.csv")?;
for result in rdr.deserialize() { let user: User = result?; println!("Usuario: {} ({} años) - {}", user.name, user.age, user.email); } Ok(())}Escritura de datos en CSV
Para escribir se utiliza csv::Writer. Ejemplo de escritura de datos estructurados:
use csv::Writer;use serde::Serialize;
#[derive(Debug, Serialize)]struct Product { id: u32, name: String, price: f64, in_stock: bool,}
fn main() -> Result<(), Box<dyn std::error::Error>> { let mut wtr = Writer::from_path("products.csv")?;
// Escribimos los encabezados wtr.write_record(&["id", "name", "price", "in_stock"])?;
// Escribimos los datos mediante serialización let products = vec![ Product { id: 1, name: "Portátil".into(), price: 75000.50, in_stock: true }, Product { id: 2, name: "Ratón".into(), price: 1500.00, in_stock: false }, ];
for product in &products { wtr.serialize(product)?; }
wtr.flush()?; println!("Datos escritos en products.csv"); Ok(())}Configuración de delimitadores y comillas
La biblioteca permite configurar el formato de manera flexible. Por ejemplo, para TSV (tabulación como delimitador):
let mut rdr = csv::ReaderBuilder::new() .delimiter(b'\\t') .flexible(true) // permitir diferente cantidad de campos .quoting(false) // deshabilitar comillas .from_reader(io::stdin());Manejo de errores y archivos grandes
Al trabajar con archivos CSV grandes, es importante considerar el rendimiento. csv utiliza lectura almacenada en búfer y no carga