Working with CSV in Rust: the csv library and data processing

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Working with CSV in Rust: the csv library and practical examples



The CSV (Comma-Separated Values) format remains one of the most popular ways to store tabular data. In Rust, there is a mature and high-performance csv library for working with CSV, which provides a convenient API for reading, writing, and processing data. In this article, we will take a detailed look at how to work efficiently with CSV in Rust.



Installation and adding the library



To start, add the dependency to your Cargo.toml file:



[dependencies]csv = "1.3"


The csv library supports working with encodings, customizable delimiters and quotes, and also provides the ability to serialize/deserialize data via serde traits.



Reading a CSV file



The simplest way to read a CSV is to use csv::Reader. Consider an example with a users.csv file:



use std::error::Error;use csv::ReaderBuilder;

fn main() -> Result<(), Box<dyn Error>> { // Create a reader with settings let mut rdr = ReaderBuilder::new() .has_headers(true) // first row is headers .delimiter(b',') // delimiter is comma .from_path("users.csv")?;

// Print headers let headers = rdr.headers()?; println!("Headers: {:?}", headers);

// Iterate over records for result in rdr.records() { let record = result?; println!("{:?}", record); } Ok(())}


Processing records with deserialization



For working with structured data, it is convenient to use deserialization into custom structs. Add serde and serde_derive:



[dependencies]csv = "1.3"serde = { version = "1.0", features = ["derive"] }


Now you can define a struct and read data directly:



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!("User: {} ({} years old) - {}", user.name, user.age, user.email); } Ok(())}


Writing data to CSV



For writing, csv::Writer is used. Example of writing structured data:



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")?;

// Write headers wtr.write_record(&["id", "name", "price", "in_stock"])?;

// Write data via serialization let products = vec![ Product { id: 1, name: "Laptop".into(), price: 75000.50, in_stock: true }, Product { id: 2, name: "Mouse".into(), price: 1500.00, in_stock: false }, ];

for product in &products { wtr.serialize(product)?; }

wtr.flush()?; println!("Data written to products.csv"); Ok(())}


Configuring delimiters and quotes



The library allows flexible format configuration. For example, for TSV (tab as delimiter):



let mut rdr = csv::ReaderBuilder::new()    .delimiter(b'\\t')    .flexible(true) // allow varying number of fields    .quoting(false) // disable quotes    .from_reader(io::stdin());


Error handling and large files



When working with large CSV files, it is important to consider performance. csv uses buffered reading and does not load

Recommendations