Skip to content

Commit

Permalink
feat: excel to csv writing
Browse files Browse the repository at this point in the history
  • Loading branch information
SilenLoc committed Mar 13, 2024
1 parent df561c3 commit 55b1eb3
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 59 deletions.
66 changes: 7 additions & 59 deletions src/from_exel/mod.rs
Original file line number Diff line number Diff line change
@@ -1,75 +1,25 @@
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<String, String> {
read(source, target)
}

fn read(source: &PathBuf, target: &PathBuf) -> Result<String, String> {
// 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<W: Write>(
_target: &mut W,
range: &Range<Data>,
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<String, String> {
read(source, target)
}

#[derive(Debug)]
struct CsvError(String);

trait CsvRowOperator {
fn operate(
self,
&mut self,
rows: impl Iterator<Item = impl Iterator<Item = CsvValue>>,
) -> Result<(), CsvError>;
}

struct PrintOperator;

impl CsvRowOperator for PrintOperator {
fn operate(
self,
rows: impl Iterator<Item = impl Iterator<Item = CsvValue>>,
) -> 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 {
Expand All @@ -78,8 +28,6 @@ impl CsvRow {
let v: CsvValue = c.into();
v
})
// done, new line
// write!(target, "\r\n")?;
}
}

Expand Down
62 changes: 62 additions & 0 deletions src/from_exel/operators.rs
Original file line number Diff line number Diff line change
@@ -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<Item = impl Iterator<Item = CsvValue>>,
) -> 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<File>,
}

impl CsvRowOperator for FileWritingOperator {
fn operate(
&mut self,
rows: impl Iterator<Item = impl Iterator<Item = CsvValue>>,
) -> Result<(), CsvError> {
let _ = rows.map(|r| {
let values: Vec<String> = 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();
}
}
36 changes: 36 additions & 0 deletions src/from_exel/read_n_x.rs
Original file line number Diff line number Diff line change
@@ -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<String, String> {
// 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<Data>, mut operator: impl CsvRowOperator) -> Result<(), CsvError> {
let all_rows = range.rows().map(CsvRow::iterator);
operator.operate(all_rows)
}

0 comments on commit 55b1eb3

Please sign in to comment.