DEV Community

BC
BC

Posted on

Day9:Read CSV File - 100DayOfRust

Today we are going to create a CLI to read a csv file that contains student score, then calculate the total and average score.

To keep the data simple, here is our examresult.csv content:

Alice, 90
Bob, 85
Chris, 92
Delan, 88
Enter fullscreen mode Exit fullscreen mode

The first column is student name and the second is score

Parse file path

To make our CLI accept an arg that user can specify the CSV file path, we use an external crate called StructOpt. With it we can easily parse command line args.

First let's create our CLI program:

cargo new readcsv
Enter fullscreen mode Exit fullscreen mode

Then go to the foler cd readcsv, add StructOpt crate to the dependencies section in Cargo.toml:

[dependencies]
structopt = "0.3"
Enter fullscreen mode Exit fullscreen mode

Read CSV File

Now let's jump to the main.rs in the src folder, add code:

use std::fs;
use std::path;
use structopt::StructOpt;

#[derive(StructOpt)]
struct Args {
    #[structopt(short="p", long="path")]
    path: path::PathBuf,
}


fn main() {
    let args = Args::from_args();
    let content = fs::read_to_string(args.path)
                      .expect("File not found");
    let mut total_score = 0;
    let mut student_count = 0;
    content.lines().for_each(|line| {
        let fields: Vec<&str> = line.split(",").collect();
        let score = fields[1].trim().parse::<i32>().unwrap();
        total_score += score;
        student_count += 1;
    });
    println!("Total score is: {}, Avg is {}", 
             total_score, 
             (total_score as f32) / (student_count as f32));
}
Enter fullscreen mode Exit fullscreen mode

You can see it is very easy to use StructOpt to collect command line args. After get the arg, we read file content to the content variable, then use a for_each iterator with a closure to calculate the total score. In the closure, we split line by "," and convert the second column value to integer. At last we print out the total and average score.

One benefit of StructOpt is, it will auto check the command line arg and print out its usage. If we use:

$ cargo run
Enter fullscreen mode Exit fullscreen mode

without specifying the CSV file path, it will generate information like below:

error: The following required arguments were not provided:
    --path <path>

USAGE:
    readcsv --path <path>
Enter fullscreen mode Exit fullscreen mode

While shows us that we need to pass --path arg. Now let's pass it:

$ cargo run -- --path=examresult.csv
Enter fullscreen mode Exit fullscreen mode

Now it succeeds, result:

Total score is: 355, Avg is 88.75
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
deciduously profile image
Ben Lovy

I know this is an exercise, but there is also a csv crate that handles this for you. I wrote an example here.

Really enjoying these write-ups!

Collapse
 
bitecode profile image
BC

Yep, I was planning to write another article about using the csv crate, but thank you for sharing this, Ben :D