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
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
Then go to the foler cd readcsv
, add StructOpt
crate to the dependencies section in Cargo.toml
:
[dependencies]
structopt = "0.3"
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));
}
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
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>
While shows us that we need to pass --path
arg. Now let's pass it:
$ cargo run -- --path=examresult.csv
Now it succeeds, result:
Total score is: 355, Avg is 88.75
Top comments (2)
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!
Yep, I was planning to write another article about using the
csv
crate, but thank you for sharing this, Ben :D