From 55b1eb3b3ed718a08bb7297d153101ee36090112 Mon Sep 17 00:00:00 2001 From: Silen Locatelli <88315530+SilenLoc@users.noreply.github.com> Date: Wed, 13 Mar 2024 08:13:21 +0100 Subject: [PATCH] feat: excel to csv writing --- src/from_exel/mod.rs | 66 ++++---------------------------------- src/from_exel/operators.rs | 62 +++++++++++++++++++++++++++++++++++ src/from_exel/read_n_x.rs | 36 +++++++++++++++++++++ 3 files changed, 105 insertions(+), 59 deletions(-) create mode 100644 src/from_exel/operators.rs create mode 100644 src/from_exel/read_n_x.rs diff --git a/src/from_exel/mod.rs b/src/from_exel/mod.rs index 3b66043..027d642 100644 --- a/src/from_exel/mod.rs +++ b/src/from_exel/mod.rs @@ -1,45 +1,13 @@ -use calamine::{open_workbook_auto, Data, Range, Reader}; -use std::fs::OpenOptions; -use std::io::{BufWriter, Write}; +use calamine::Data; use std::path::PathBuf; -pub fn all(source: &PathBuf, target: &PathBuf) -> Result { - read(source, target) -} - -fn read(source: &PathBuf, target: &PathBuf) -> Result { - // find source file - let sce = PathBuf::from(source); - match sce.extension().and_then(|s| s.to_str()) { - Some("xlsx" | "xlsm" | "xlsb" | "xls") => (), - _ => panic!("Expecting an excel file"), - } - - // create or append to target file - let target_path = PathBuf::from(target).with_extension("csv"); - let target_file = OpenOptions::new() - .create(true) - .append(true) - .open(target_path) - .unwrap(); - let mut target = BufWriter::new(target_file); +use self::read_n_x::read; - // open xl file - let mut xl = open_workbook_auto(&sce).unwrap(); - let range = xl.worksheet_range_at(0).unwrap().unwrap(); - - write_range(&mut target, &range, PrintOperator {}) - .map(|()| "All done".to_owned()) - .map_err(|err| err.0) -} +mod operators; +mod read_n_x; -fn write_range( - _target: &mut W, - range: &Range, - operator: impl CsvRowOperator, -) -> Result<(), CsvError> { - let all_rows = range.rows().map(CsvRow::iterator); - operator.operate(all_rows) +pub fn all(source: &PathBuf, target: &PathBuf) -> Result { + read(source, target) } #[derive(Debug)] @@ -47,29 +15,11 @@ struct CsvError(String); trait CsvRowOperator { fn operate( - self, + &mut self, rows: impl Iterator>, ) -> Result<(), CsvError>; } -struct PrintOperator; - -impl CsvRowOperator for PrintOperator { - fn operate( - self, - rows: impl Iterator>, - ) -> Result<(), CsvError> { - rows.for_each(|r| { - println!("---new row---"); - r.for_each(|v| match v.0 { - Ok(k) => println!("{k}"), - Err(e) => println!("{e}"), - }); - }); - Ok(()) - } -} - struct CsvRow; impl CsvRow { @@ -78,8 +28,6 @@ impl CsvRow { let v: CsvValue = c.into(); v }) - // done, new line - // write!(target, "\r\n")?; } } diff --git a/src/from_exel/operators.rs b/src/from_exel/operators.rs new file mode 100644 index 0000000..97f4851 --- /dev/null +++ b/src/from_exel/operators.rs @@ -0,0 +1,62 @@ +use std::{ + fs::File, + io::{BufWriter, Write}, +}; + +use super::{CsvError, CsvRowOperator, CsvValue}; + +pub struct PrintOperator; + +impl CsvRowOperator for PrintOperator { + fn operate( + &mut self, + rows: impl Iterator>, + ) -> Result<(), CsvError> { + rows.for_each(|r| { + println!("---new row---"); + r.for_each(|v| match v.0 { + Ok(k) => println!("{k}"), + Err(e) => println!("{e}"), + }); + }); + Ok(()) + } +} + +pub struct FileWritingOperator { + pub(crate) writer: BufWriter, +} + +impl CsvRowOperator for FileWritingOperator { + fn operate( + &mut self, + rows: impl Iterator>, + ) -> Result<(), CsvError> { + let _ = rows.map(|r| { + let values: Vec = r.filter_map(|v| v.0.ok()).collect(); + let len = values.len(); + + let _ = values.iter().enumerate().map(|(n, v)| { + self.write(v); + if n != len { + self.sep(";"); + } + }); + + self.end_line(); + }); + Ok(()) + } +} + +impl FileWritingOperator { + fn write(&mut self, value: &str) { + let _ = write!(&mut self.writer, "{value}").map_err(|err| CsvError(err.to_string())); + } + fn end_line(&mut self) { + write!(self.writer, "\r\n").unwrap(); + } + fn sep(&mut self, sep: &str) { + write!(self.writer, "{sep}").unwrap(); + } +} diff --git a/src/from_exel/read_n_x.rs b/src/from_exel/read_n_x.rs new file mode 100644 index 0000000..0d54561 --- /dev/null +++ b/src/from_exel/read_n_x.rs @@ -0,0 +1,36 @@ +use std::{fs::OpenOptions, io::BufWriter, path::PathBuf}; + +use calamine::{open_workbook_auto, Data, Range, Reader}; + +use super::{operators::FileWritingOperator, CsvError, CsvRow, CsvRowOperator}; + +pub fn read(source: &PathBuf, target: &PathBuf) -> Result { + // find source file + let sce = PathBuf::from(source); + match sce.extension().and_then(|s| s.to_str()) { + Some("xlsx" | "xlsm" | "xlsb" | "xls") => (), + _ => panic!("Expecting an excel file"), + } + + // create or append to target file + let target_path = PathBuf::from(target).with_extension("csv"); + let target_file = OpenOptions::new() + .create(true) + .append(true) + .open(target_path) + .unwrap(); + let target = BufWriter::new(target_file); + + // open xl file + let mut xl = open_workbook_auto(&sce).unwrap(); + let range = xl.worksheet_range_at(0).unwrap().unwrap(); + + write_range(&range, FileWritingOperator { writer: target }) + .map(|()| "All done".to_owned()) + .map_err(|err| err.0) +} + +fn write_range(range: &Range, mut operator: impl CsvRowOperator) -> Result<(), CsvError> { + let all_rows = range.rows().map(CsvRow::iterator); + operator.operate(all_rows) +}