XlsxBatchReader
An Excel/OpenDocument Spreadsheets file batch reader, in pure Rust. This crate supports Office 2007 or newer file formats(xlsx, xlsm, etc). The most obvious difference from other Excel file reading crates is that it does not read the whole file into memory, but read in batches. So that it can maintain low memory usage, especially when reading large files.
This crate supports date and time recognition, as well as obtaining merged cell ranges. For faster speed, it only supports reading data, not support formulas and other styles.
Examples
- simple reader
use xlsx_batch_reader::{get_ord_from_tuple, read::XlsxBook, MAX_COL_NUM};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut book = XlsxBook::new("xlsx/test.xlsx", true)?;
for shname in book.get_visible_sheets().clone() {
let sheet = book.get_sheet_by_name(&shname, 100, 0, 1, MAX_COL_NUM, false)?;
for batch in sheet {
let (rows_nums, rows_data) = batch?;
for (row, cells) in rows_nums.into_iter().zip(rows_data) {
for (col, cel) in cells.into_iter().enumerate() {
let val: String = cel.get()?.unwrap();
println!("the value of {} is {val}; raw cell is {:?}", get_ord_from_tuple(row, (col+1) as u16)?, cel);
}
}
};
}
Ok(())
}
possible output:
the value of A1 is a; raw cell is Shared("a")
the value of B1 is ; raw cell is Blank
the value of C1 is c; raw cell is Shared("c")
the value of D1 is d; raw cell is Shared("d")
the value of A2 is 1; raw cell is Number(1.0)
the value of B2 is ; raw cell is Blank
the value of C2 is s; raw cell is Shared("s")
the value of A4 is 2024-01-04; raw cell is Date(45295.58405092593)
the value of B4 is ; raw cell is Blank
the value of C4 is 4; raw cell is Number(4.0)
- merged ranges
use xlsx_batch_reader::{get_num_from_ord, is_merged_cell, read::XlsxBook};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut book = XlsxBook::new("xlsx/test.xlsx", true)?;
for shname in book.get_visible_sheets().clone() {
let mut sheet = book.get_sheet_by_name(&shname, 100, 0, 1, get_num_from_ord("C".as_bytes())?, true)?;
let (_, _header) = sheet.get_header_row()?;
if let Some((_rows_nums, _rows_data)) = sheet.get_remaining_cells()? {
};
let merged_rngs = sheet.get_merged_ranges()?;
match is_merged_cell(merged_rngs, 2, get_num_from_ord("A".as_bytes())?) {
(true, None) => {
println!("a merged cell(not top left cell)");
},
(true, Some((nrow, ncol))) => {
println!("a merged cell(top left cell), taking {nrow} row(s) and {ncol} column(s)");
},
_ => {
println!("not a merged cell");
}
}
}
Ok(())
}
possible output:
a merged cell(top left cell), taking 2 row(s) and 2 column(s)
- read date and time
use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
use xlsx_batch_reader::{read::XlsxBook, MAX_COL_NUM};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut book = XlsxBook::new("xlsx/test.xlsx", true)?;
for shname in book.get_visible_sheets().clone() {
let mut sheet = book.get_sheet_by_name(&shname, 100, 3, 1, MAX_COL_NUM, false)?;
if let Some((_, rows_data)) = sheet.get_remaining_cells()? {
let row = &rows_data[0];
let val_dt: NaiveDate = row[0].get()?.unwrap();
let val_tm: NaiveTime = row[0].get()?.unwrap();
let val_dttm: NaiveDateTime = row[0].get()?.unwrap();
let val_stamp: Timestamp = row[0].get()?.unwrap(); println!("date:{}\ntime:{}\ndatetime:{}\ntimestamp:{}", val_dt, val_tm, val_dttm, val_stamp.utc());
};
}
Ok(())
}
possible output:
date:2024-01-04
time:14:01:02
datetime:2024-01-04 14:01:02
timestamp:1704376862
- simple batch writer (feature xlsxwriter should be enabled)
use xlsx_batch_reader::{get_num_from_ord, read::XlsxBook, write::XlsxWriter};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut writer = XlsxWriter::new();
let mut book = XlsxBook::new("xlsx/test.xlsx", true)?;
for shname in book.get_visible_sheets().clone() {
let mut sheet = book.get_sheet_by_name(&shname, 100, 0, 1, get_num_from_ord("C".as_bytes())?, true)?;
let pre_cells = vec![shname];
if let Some((rows_nums, rows_data)) = sheet.get_remaining_cells()? {
writer.append_rows("sheet", rows_nums, rows_data, &pre_cells)?;
};
};
writer.save_as("xlsx/out.xlsx")?;
Ok(())
}