First of all, I'm not a programmer but only a sysadmin doing more complex tasks in PHP-CLI (forgive me ).
I'm very interested in doing more stuff in Rust, so as an exercise I tried to "convert" a CSV file into a TAB separated file. This is easy enough in PHP:
csv.php:
#!/usr/bin/php
<?php
while ( ( $data = fgetcsv( STDIN ) ) !== FALSE ) {
echo implode( "\t", $data ) . "\n";
}
After a lot of googling and going through some of the docs, I came up with this solution:
Cargo.toml:
[package]
name = "csv-test"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
csv = "1.1.6"
src/main.rs:
use std::error::Error;
use std::io;
use std::process;
fn example() -> Result<(), Box<dyn Error>> {
let mut rdr = csv::ReaderBuilder::new()
.flexible(true)
.has_headers(false)
.from_reader(io::stdin());
for result in rdr.records() {
// The iterator yields Result<StringRecord, Error>, so we check the error here.
let record = result?;
// the following block appends a tab to the last field, which it not what i want
/*for field in &record {
print!("{}\t", field);
}*/
let record_vector: Vec<_> = record.iter().collect();
print!("{}", record_vector.join("\t"));
println!();
}
Ok(())
}
fn main() {
if let Err(err) = example() {
println!("error running example: {}", err);
process::exit(1);
}
}
Surprisingly enough, this works! But the PHP version yields the same result and is faster:
[pigpen@shuttle:~/rust_projects/csv-test]$ time cat test.csv | ./csv.php > /tmp/foo.php
real 0m2.198s
user 0m1.862s
sys 0m0.354s
[pigpen@shuttle:~/rust_projects/csv-test]$ time cat test.csv | ./target/debug/csv-test > /tmp/f
oo.rust
real 0m3.512s
user 0m3.120s
sys 0m0.415s
I'm sure, I'm doing things all wrong, so here are my three questions:
What is the most idiomatic way to do this in Rust?
What is the most concise way to do it in Rust?
What is the most performant way?
Thank you in advance,
Marc