【Rust每周一库】csv – 文件读写库

  • 2020 年 2 月 20 日
  • 筆記

这次搬运的库是很多数据分析师、数据科学家、以及金融分析师常用的csv文件库。

csv

用Rust实现的一个高性能、灵活的CSV读写器,支持Serde.

官方文档:

https://docs.rs/csv

使用方法:

将以下配置加进你的 Cargo.toml:

[dependencies]  csv = "1.1"  

例子:

简单示范如何从stdin读取CSV数据并通过stdout将每一条记录打印出来。

use std::error::Error;  use std::io;  use std::process;    fn example() -> Result<(), Box<dyn Error>> {      // 建立 CSV 读取器并且遍历每一条记录。      let mut rdr = csv::Reader::from_reader(io::stdin());      for result in rdr.records() {          // 遍历器会返回Result<StringRecord, Error>,所以我们在这里检查是否有错误。          let record = result?;          println!("{:?}", record);      }      Ok(())  }    fn main() {      if let Err(err) = example() {          println!("error running example: {}", err);          process::exit(1);      }  }  

以上的例子可以用以下命令运行:

$ git clone git://github.com/BurntSushi/rust-csv  $ cd rust-csv  $ cargo run --example cookbook-read-basic < examples/data/smallpop.csv  

与 Serde一起使用时:

示范如何从stdin读取CSV数据并且将数据映射到定制结构体。结构体中的成员名称会默认与CSV数据中的表头相对应。

use std::error::Error;  use std::io;  use std::process;    use serde::Deserialize;    #[derive(Debug, Deserialize)]  struct Record {      city: String,      region: String,      country: String,      population: Option<u64>,  }    fn example() -> Result<(), Box<dyn Error>> {      let mut rdr = csv::Reader::from_reader(io::stdin());      for result in rdr.deserialize() {          // 这里需要注意,我们需要为自动反序列化提供一个类型提示          let record: Record = result?;          println!("{:?}", record);      }      Ok(())  }    fn main() {      if let Err(err) = example() {          println!("error running example: {}", err);          process::exit(1);      }  }  

以上的例子可以用以下命令运行:

$ git clone git://github.com/BurntSushi/rust-csv  $ cd rust-csv  $ cargo run --example cookbook-read-serde < examples/data/smallpop.csv  

下面的例子演示了如何将数据以CSV数据形式写入stdout:

extern crate csv;    use std::error::Error;  use std::io;  use std::process;    fn example() -> Result<(), Box<Error>> {      let mut wtr = csv::Writer::from_writer(io::stdout());        // 当不与Serde共同使用时,表头可以按照与其他记录同样的方式写入      wtr.write_record(&["city", "region", "country", "population"])?;      wtr.write_record(&["Southborough", "MA", "United States", "9686"])?;      wtr.write_record(&["Northbridge", "MA", "United States", "14061"])?;      wtr.flush()?;      Ok(())  }    fn main() {      if let Err(err) = example() {          println!("error running example: {}", err);          process::exit(1);      }  }  

以上的例子可以用以下命令运行:

$ git clone git://github.com/BurntSushi/rust-csv  $ cd rust-csv  $ cargo run --example cookbook-write-basic > /tmp/simplepop.csv  

与Serde一起使用时:

extern crate csv;  #[macro_use]  extern crate serde_derive;    use std::error::Error;  use std::io;  use std::process;    #[derive(Debug, Serialize)]  struct Record {      city: String,      region: String,      country: String,      population: Option<u64>,  }    fn example() -> Result<(), Box<Error>> {      let mut wtr = csv::Writer::from_writer(io::stdout());        // 当用结构体通过Serde写入记录时,表头会被自动写入      wtr.serialize(Record {          city: "Southborough".to_string(),          region: "MA".to_string(),          country: "United States".to_string(),          population: Some(9686),      })?;      wtr.serialize(Record {          city: "Northbridge".to_string(),          region: "MA".to_string(),          country: "United States".to_string(),          population: Some(14061),      })?;      wtr.flush()?;      Ok(())  }    fn main() {      if let Err(err) = example() {          println!("error running example: {}", err);          process::exit(1);      }  }  

以上的例子可以用以下命令运行:

$ git clone git://github.com/BurntSushi/rust-csv  $ cd rust-csv  $ cargo run --example cookbook-write-serde > /tmp/simplepop.csv  

例子:用过滤器搜索

extern crate csv;    use std::env;  use std::error::Error;  use std::io;  use std::process;    fn run() -> Result<(), Box<Error>> {      // 通过位置参数拿到查询语句      let query = match env::args().nth(1) {          None => return Err(From::from("expected 1 argument, but got none")),          Some(query) => query,      };        // 通过stdin建立CSV读取器      // 通过stdout建立CSV写入器      let mut rdr = csv::Reader::from_reader(io::stdin());      let mut wtr = csv::Writer::from_writer(io::stdout());        // 在读取数据记录之前,先写入表头记录      wtr.write_record(rdr.headers()?)?;        // 通过rdr遍历所有记录,然后通过wre写入只含有“query”的记录      for result in rdr.records() {          let record = result?;          if record.iter().any(|field| field == &query) {              wtr.write_record(&record)?;          }      }        // CSV写入器使用内部缓冲器,要记得完成后刷新清空。      wtr.flush()?;      Ok(())  }    fn main() {      if let Err(err) = run() {          println!("{}", err);          process::exit(1);      }  }  

在编译之后,运行这段代码时加入 MA 作为查询语句,可以看到结果中只有一条记录复合查询条件:

$ cargo build  $ ./csvtutor MA < uspop.csv  City,State,Population,Latitude,Longitude  Reading,MA,23441,42.5255556,-71.0958333  

本文来源于 cookbook.