• X-CSV-Reader:一个使用Rust实现CSV命令行读取器


    🎈效果演示

    csv

    ⚡️快速上手

    • 依赖导入:
    cargo add csv
    
    • 读取实现:
    use std::error::Error;
    use std::fs::File;
    use std::path::Path;
    
    fn read_csv<P: AsRef<Path>>(filename: P) -> Result<(), Box<dyn Error>> {
        let file = File::open(filename)?;
        let mut rdr = csv::Reader::from_reader(file);
    
        for result in rdr.records() {
            let record = result?;
            println!("{:?}", record);
        }
    
        Ok(())
    }
    
    fn main() -> Result<(), Box<dyn Error>> {
        let filename = "src/email.csv";
        read_csv(filename)
    }
    

    这是一段简单的Rust程序,演示了如何使用csv``crate中的读取API,通过指定csv路径进行csv数据的读取。

    1. use std::error::Error;, use std::fs::File;, use std::path::Path;

      • 这些是Rust语言中用于导入标准库中的错误处理、文件操作和路径相关模块的语句。
    2. fn read_csv>(filename: P) -> Result<(), Box>

      • 这是一个函数定义,名为read_csv,它接受一个实现了AsRef trait 的泛型参数P,表示文件名。函数返回一个Result枚举类型,其中Ok(())表示成功,Err包含一个实现了Error trait 的错误对象的Box指针。
      • 函数打开指定的CSV文件,创建一个CSV读取器(csv::Reader),然后遍历文件中的每一行记录并打印出来。
    3. fn main() -> Result<(), Box>

      • 这是程序的入口点,也是主函数。它也返回一个Result枚举类型,用于处理可能出现的错误。
      • main函数中,指定了要读取的CSV文件的文件名为"src/email.csv",然后调用read_csv函数来处理这个文件。
    4. let file = File::open(filename)?;

      • read_csv函数中,这行代码尝试打开指定的文件,?操作符用于处理可能出现的错误,如果出现错误,则会将错误传播到调用方。
    5. let mut rdr = csv::Reader::from_reader(file);

      • 创建一个CSV读取器rdr,并从打开的文件中读取数据。
    6. for result in rdr.records() { ... }

      • 使用for循环遍历CSV文件中的每一行记录。
    7. let record = result?;

      • 在循环中,尝试将每一行记录解析为csv::StringRecord类型的record?操作符用于处理可能的解析错误。
    8. println!("{:?}", record);

      • 打印每一行记录的内容。
    9. Ok(())

      • 在函数末尾,返回一个Ok(())表示函数执行成功。

    • 读取结果:

    image-20240526192615414

    csv文件的读取功能基本实现了,但是每次读取需要我们手动修改代码,指定要读取的csv文件路径,相对还是不够实用和灵活,特别是对于非程序猿来说。下面将对代码进行进一步提取和优化,将读取的功能封装为命令行程序,提升使用体验。


    💥命令行程序封装

    关于命令行,Rustcrate中有很多不错的库,在之前我的文章中也提及了部分,这里选择使用clap这个crate来实现。

    [dependencies]
    ansi_term = "0.12.1"
    clap = { version = "4.5.4", features = ["derive"] }
    csv = "1.3.0"
    prettytable-rs = "0.10.0"
    
    • 结构分离,为了利于维护,将读取CSV文件的方法独立在lib.rs中,命令行参数处理等内容依旧在main.rs

    • lib.rs

    pub fn read_csv<P: AsRef<Path>>(filename: P) -> Result<(), Box<dyn Error>> {
        let file = File::open(filename)?;
        let mut rdr = csv::Reader::from_reader(file);
    
        let mut table = Table::new();
    
        // 添加表头
        let headers = rdr
            .headers()?
            .iter()
            .map(|h| Cell::new(h).style_spec("Fg=green"))
            .collect();
        table.add_row(Row::new(headers));
    
        // 添加记录
        for result in rdr.records() {
            let record = result?;
            let cells: Vec<Cell> = record.iter().map(|field| Cell::new(field)).collect();
            table.add_row(Row::new(cells));
        }
    
        table.printstd();
        Ok(())
    }
    

    感觉没啥新的东西可以讲的,这个方法的主要逻辑在上面已经说过,至于内容的打印,还是使用之前在X-SCAN端口扫描器中使用的Table进行美化。

    • main.rs
    use x_csvreader::read_csv;
    #[derive(Parser, Debug)]
    struct Args {
        #[clap(short, long, help = "The path to the CSV file.")]
        path: String,
    }
    fn print_infos() {
        println!(
            "{}",
            Blue.paint(
                r#"
                __   __      _____  _______      __     _____                _
                \ \ / /     / ____|/ ____\ \    / /    |  __ \              | |
                 \ V /_____| |    | (___  \ \  / /_____| |__) |___  __ _  __| | ___ _ __
                  > <______| |     \___ \  \ \/ /______|  _  // _ \/ _` |/ _` |/ _ \ '__|
                 / . \     | |____ ____) |  \  /       | | \ \  __/ (_| | (_| |  __/ |
                /_/ \_\     \_____|_____/    \/        |_|  \_\___|\__,_|\__,_|\___|_|
            author:代号0408
            version:0.1.0
            "#
            )
        );
    }
    fn main() {
        print_infos();
        let args = Args::parse();
        // 调用lib.rs中定义的read_csv函数
        match read_csv(&args.path) {
            Ok(_) => {
                println!("=============================");
                println!("CSV 文件读取成功!");
            }
            Err(e) => {
                eprintln!("读取 CSV 文件时出现错误:{}", e);
            }
        }
    }
    

    逻辑简单,就不赘述了。如果不了解字符打印美化和表格美化这两个lib基本使用的,建议翻下我往期的文章,都是有写的。

    那么如何使用呢?

    cargo run -- --path 
    

    不妨将开头的效果复现一下:

    cargo run -- --path C:\RustProjects\x-csvreader\src\email.csv
    

    当然,为了演示的效果,这里选择的CSV文件数据量并不大,处理大数据量的文件也是可以的,只不过打印出来的表格数据可能会出现终端 霸屏的情况,纸上得来终觉浅!建议你自己试试,这里就不截图了。


    📃总结

    这篇文章主要学习如何基于Rust使用csv这个crate构建一个CSV文件读取器的过程。学习了csv相关的用法以及一些往期学过的crate的复习,兼顾了实用性和Rust的学习,是个很不错的练手小项目。


    🔖相关资源

  • 相关阅读:
    ResNet网络详解
    Redis数据结构和类型
    GBase 8d的特性-可扩展性
    笔记 | MySQL 运维常用语句
    Python中import的as语法
    自动化测试框架Pytest(五) —— 接口关联数据
    使用 Qt for Android 获取并利用手机传感器数据(下篇)使用C++实现功能
    【TypeScript】类型兼容:如何判断一个类型是否可以赋值给其他类型?
    ISP代理是什么?跨境账号养号为什么要选择它?
    vue使用.filter方法检索数组中指定时间段内的数据
  • 原文地址:https://blog.csdn.net/2302_76401343/article/details/139225222