用于处理CSV文件的Rust库:csv
CSV(逗号分隔值)是存储表格数据最常用的格式之一。在Rust中,有一个强大、灵活且高性能的库csv用于处理CSV,它是BurntSushi(ripgrep和regex的作者)生态系统的一部分。它允许以最小的代价和最大的类型安全性来读取、写入、序列化和反序列化数据。
安装
在Cargo.toml中添加依赖:
[dependencies]csv = "1.3"对于结构的序列化/反序列化,还需要serde:
[dependencies]csv = "1.3"serde = { version = "1.0", features = ["derive"] }库的主要功能
- 读取和写入,支持自定义分隔符、引号和转义字符。
- 自动处理表头——按列名操作。
- 通过
serde进行序列化/反序列化——将CSV行转换为强类型的Rust结构。 - 灵活的错误处理——错误定位(行号、列号)。
- 流式处理——处理大文件而无需全部加载到内存。
- 支持非UTF-8编码(通过外部crate,例如
encoding)。
读取CSV文件
读取CSV最简单的方法是使用Reader和记录迭代器。
示例1:无表头读取
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(())}示例2:有表头读取
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(())}使用Serde进行强类型化
最方便的方法是定义一个带有#[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(())}这保证了数据会自动转换为所需的类型。例如,如果age字段中出现了字符串"abc",程序将返回错误,并指明行和列。
写入CSV文件
写入使用Writer。可以写入原始字符串,也可以写入序列化后的结构。
示例:通过结构写入
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