你绝对想不到rust处理csv数据还能这么玩

278 阅读3分钟

由于上篇写的序列化给大家造成一些困惑或者是词不达意,亦或是给大家理解序列化造成了一定的误解,我深感抱歉,序列化我将重新构思来写,然后把底层的核心原理以及设计思想都会讲清楚,还请大家耐心等待,今天给大家带来使用rust读取csv文件的知识,我们知道csv可以直接导入到数据库,使用逗号分隔开,还能和excel兼容,因此在一些数据处理上常会用到它,我们有必要一探究竟。

将记录序列化为 CSV

我们通过一个例子来展示如何序列化 Rust 元组。csv::writer 支持从 Rust 类型到 CSV 记录的自动序列化。write_record 只写入包含字符串数据的简单记录。具有更复杂值(如数字、浮点和选项)的数据使用 serialize 进行序列化。因为 csv::writer 使用内部缓冲区,所以在完成时总是显式刷新 flush。

use error_chain::error_chain;

use std::io;

error_chain! {
    foreign_links {
        CSVError(csv::Error);
        IOError(std::io::Error);
   }
}

fn main() -> Result<()> {
    let mut wtr = csv::Writer::from_writer(io::stdout());

    wtr.write_record(&["Name""Place""ID"])?;

    wtr.serialize(("Mark""Sydney"87))?;
    wtr.serialize(("Ashley""Dublin"32))?;
    wtr.serialize(("Akshat""Delhi"11))?;

    wtr.flush()?;
    Ok(())
}

用 Serde 将记录序列化为 CSV

serde和csv结合会擦出什么火花了?下面的实例展示如何使用 serde crate 将自定义结构体序列化为 CSV 记录。

use error_chain::error_chain;
use serde::Serialize;
use std::io;

error_chain! {
   foreign_links {
       IOError(std::io::Error);
       CSVError(csv::Error);
   }
}

#[derive(Serialize)]
struct Record<'a> {
    name: &'a str,
    place: &'a str,
    id: u64,
}

fn main() -> Result<()> {
    let mut wtr = csv::Writer::from_writer(io::stdout());

    let rec1 = Record { name: "Mark", place: "Melbourne", id: 56};
    let rec2 = Record { name: "Ashley", place: "Sydney", id: 64};
    let rec3 = Record { name: "Akshat", place: "Delhi", id: 98};

    wtr.serialize(rec1)?;
    wtr.serialize(rec2)?;
    wtr.serialize(rec3)?;

    wtr.flush()?;

    Ok(())
}

转换CSV文件的列

包含颜色名称和十六进制颜色值的 CSV 文件转换为具有颜色名称和 rgb 颜色值的 CSV 文件。使用 csv crate 读写 csv 文件,使用 serde crate 对行输入字节进行反序列化,对行输出字节进行序列化。

详细请参阅 csv::Reader::deserialize、serde::Deserialize,以及 std::str::FromStr

use error_chain::error_chain;
use csv::{Reader, Writer};
use serde::{de, Deserialize, Deserializer};
use std::str::FromStr;

error_chain! {
   foreign_links {
       CsvError(csv::Error);
       ParseInt(std::num::ParseIntError);
       CsvInnerError(csv::IntoInnerError<Writer<Vec<u8>>>);
       IO(std::fmt::Error);
       UTF8(std::string::FromUtf8Error);
   }
}

#[derive(Debug)]
struct HexColor {
    red: u8,
    green: u8,
    blue: u8,
}

#[derive(Debug, Deserialize)]
struct Row {
    color_name: String,
    color: HexColor,
}

impl FromStr for HexColor {
    type Err = Error;

    fn from_str(hex_color: &str-> std::result::Result<SelfSelf::Err> {
        let trimmed = hex_color.trim_matches('#');
        if trimmed.len() != 6 {
            Err("Invalid length of hex string".into())
        } else {
            Ok(HexColor {
                red: u8::from_str_radix(&trimmed[..2], 16)?,
                green: u8::from_str_radix(&trimmed[2..4], 16)?,
                blue: u8::from_str_radix(&trimmed[4..6], 16)?,
            })
        }
    }
}

impl<'de> Deserialize<'defor HexColor {
    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        FromStr::from_str(&s).map_err(de::Error::custom)
    }
}

fn main() -> Result<()> {
    let data = "color_name,color
red,#ff0000
green,#00ff00
blue,#0000FF
periwinkle,#ccccff
magenta,#ff00ff"
        .to_owned();
    let mut out = Writer::from_writer(vec![]);
    let mut reader = Reader::from_reader(data.as_bytes());
    for result in reader.deserialize::<Row>() {
        let res = result?;
        out.serialize((
            res.color_name,
            res.color.red,
            res.color.green,
            res.color.blue,
        ))?;
    }
    let written = String::from_utf8(out.into_inner()?)?;
    assert_eq!(Some("magenta,255,0,255"), written.lines().last());
    println!("{}", written);
    Ok(())
}

最后希望大家能关注我的公众号:花说编程

扫码_搜索联合传播样式-标准色版.png