### Read and Iterate XLSX with openpyxl (Python) Source: https://github.com/tafia/calamine/blob/master/README.md Provides an example of opening an XLSX file and iterating through its rows using the openpyxl library in Python. The 'openpyxl' package must be installed. ```python from openpyxl import load_workbook # Open workbook wb = load_workbook( filename=r'NYC_311_SR_2010-2020-sample-1M.xlsx', read_only=True) # Get worksheet ws = wb['NYC_311_SR_2010-2020-sample-1M'] # Iterate over rows for row in ws.rows: _ = row # Close the workbook after reading wb.close() ``` -------------------------------- ### Read and Iterate XLSX with Excelize (Go) Source: https://github.com/tafia/calamine/blob/master/README.md Shows how to open an XLSX file and iterate through its rows using the Excelize library in Go. Requires the 'excelize' package to be installed. ```go package main import ( "fmt" "github.com/xuri/excelize/v2" ) func main() { // Open workbook file, err := excelize.OpenFile(`NYC_311_SR_2010-2020-sample-1M.xlsx`) if err != nil { fmt.Println(err) return } defer func() { // Close the spreadsheet. if err := file.Close(); err != nil { fmt.Println(err) } }() // Select worksheet rows, err := file.Rows("NYC_311_SR_2010-2020-sample-1M") if err != nil { fmt.Println(err) return } // Iterate over rows for rows.Next() { } } ``` -------------------------------- ### Basic Spreadsheet Deserialization Source: https://github.com/tafia/calamine/blob/master/README.md Shows how to open a workbook, get a worksheet range, and deserialize records from it. This example assumes a simple structure where each row can be directly deserialized into a tuple. ```rust use calamine::{open_workbook, Error, Xlsx, Reader, RangeDeserializerBuilder}; fn example() -> Result<(), Error> { let path = format!("{}/tests/temperature.xlsx", env!("CARGO_MANIFEST_DIR")); let mut workbook: Xlsx<_> = open_workbook(path)?; let range = workbook.worksheet_range("Sheet1")?; let mut iter = RangeDeserializerBuilder::new().from_range(&range)?; if let Some(result) = iter.next() { let (label, value): (String, f64) = result?; assert_eq!(label, "celsius"); assert_eq!(value, 22.2222); Ok(()) } else { Err(From::from("expected at least one record but got none")) } } ``` -------------------------------- ### Read Spreadsheet Rows Source: https://github.com/tafia/calamine/blob/master/README.md A simple example of reading rows from a spreadsheet using the `Reader` trait. It iterates through each row and prints its content, focusing on the first cell. ```rust use calamine::{Reader, Xlsx, open_workbook}; let mut excel: Xlsx<_> = open_workbook("file.xlsx").unwrap(); if let Ok(r) = excel.worksheet_range("Sheet1") { for row in r.rows() { println!("row={:?}, row[0]={:?}", row, row[0]); } } ``` -------------------------------- ### Extract Embedded Images with `Reader::pictures` Source: https://context7.com/tafia/calamine/llms.txt Enable the `picture` feature in Cargo.toml to use the `pictures()` method. This method returns raw image bytes and their file extensions for each embedded picture. The example demonstrates iterating through pictures, printing their details, and saving them to disk. ```rust use calamine::{open_workbook, Reader, Xlsx}; use std::fs; fn main() -> Result<(), Box> { let wb: Xlsx<_> = open_workbook("tests/picture.xlsx")?; if let Some(pictures) = wb.pictures() { for (idx, (ext, data)) in pictures.iter().enumerate() { println!("Picture {}: type={ext}, size={} bytes", idx, data.len()); // Save to disk. fs::write(format!("picture_{idx}.{ext}"), data)?; } } else { println!("No pictures found."); } Ok(()) } ``` -------------------------------- ### Format-Specific Workbook Structs (`Xlsx`, `Xls`, `Xlsb`, `Ods`) Source: https://context7.com/tafia/calamine/llms.txt Use dedicated typed structs for known spreadsheet formats (Xlsx, Xlsb, Xls, Ods) for better type inference and error messages. `XlsOptions` can be used to tune legacy XLS parsing. Each example shows opening a workbook and accessing its worksheet range. ```rust use calamine::{open_workbook, Reader, Xlsx, Xls, Xlsb, Ods, XlsOptions}; fn read_xlsx() -> Result<(), Box> { let mut wb: Xlsx<_> = open_workbook("file.xlsx")?; let range = wb.worksheet_range("Sheet1")?; println!("xlsx rows: {}", range.height()); Ok(()) } ``` ```rust fn read_xlsb() -> Result<(), Box> { let mut wb: Xlsb<_> = open_workbook("file.xlsb")?; let range = wb.worksheet_range("Sheet1")?; println!("xlsb rows: {}", range.height()); Ok(()) } ``` ```rust // XlsOptions can be passed for legacy format tuning. let mut wb: Xls<_> = open_workbook("file.xls")?; let range = wb.worksheet_range("Sheet1")?; println!("xls rows: {}", range.height()); Ok(()) } ``` ```rust fn read_ods() -> Result<(), Box> { let mut wb: Ods<_> = open_workbook("file.ods")?; let range = wb.worksheet_range("Sheet1")?; println!("ods rows: {}", range.height()); Ok(()) } ``` -------------------------------- ### Dynamic Multi-Format Workbook with `Sheets` Enum Source: https://context7.com/tafia/calamine/llms.txt The `Sheets` enum, returned by `open_workbook_auto`, provides a format-agnostic interface. It delegates `Reader` trait calls to the correct inner format at runtime. This example iterates through all sheet names, reads each worksheet's range, and prints rows as CSV-formatted strings. ```rust use calamine::{open_workbook_auto, Reader, Data}; use std::path::Path; fn export_to_csv(path: &Path) -> Result<(), Box> { // Sheets> implements the full Reader trait. let mut wb = open_workbook_auto(path)?; let sheets = wb.sheet_names().to_owned(); for sheet_name in sheets { println!("=== {sheet_name} ==="); let range = wb.worksheet_range(&sheet_name)?; for row in range.rows() { let csv_row: Vec = row.iter().map(|c| match c { Data::Empty => String::new(), other => other.to_string(), }).collect(); println!("{}", csv_row.join(",")); } } Ok(()) } ``` -------------------------------- ### Enable Calamine Crate Features Source: https://github.com/tafia/calamine/blob/master/README.md Shows how to enable optional features for the `calamine` crate, such as `chrono` for date/time support, using Cargo.toml. ```bash cargo add calamine -F chrono ``` -------------------------------- ### Open Workbook with Runtime Format Detection (Rust) Source: https://context7.com/tafia/calamine/llms.txt Detects the file format from the file extension (or by brute-force probing when the extension is unknown) and returns a Sheets> enum. Use this when the file format is not known until runtime. ```rust use calamine::{open_workbook_auto, Reader, Data}; fn main() -> Result<(), Box> { // Works with .xls, .xlsx, .xlsm, .xlsb, .ods, or unknown extensions. let mut workbook = open_workbook_auto("path/to/spreadsheet.xlsx")?; // Access metadata: sheet names and defined names. for name in workbook.sheet_names() { println!("Sheet: {name}"); } for (name, formula) in workbook.defined_names() { println!("Defined name '{name}' = {formula}"); } // Iterate over all worksheets at once. for (sheet_name, range) in workbook.worksheets() { let (rows, cols) = range.get_size(); println!("Sheet '{sheet_name}': {rows} rows, {cols} cols"); let non_empty = range.used_cells().count(); println!(" Non-empty cells: {non_empty}"); } Ok(()) } ``` -------------------------------- ### Read and Iterate XLSX with Calamine (Rust) Source: https://github.com/tafia/calamine/blob/master/README.md Demonstrates opening an XLSX workbook and iterating over its rows using the Calamine library in Rust. Ensure the 'calamine' crate is added as a dependency. ```rust use calamine::{open_workbook, Reader, Xlsx}; fn main() { // Open workbook let mut excel: Xlsx<_> = open_workbook("NYC_311_SR_2010-2020-sample-1M.xlsx").expect("failed to find file"); // Get worksheet let sheet = excel .worksheet_range("NYC_311_SR_2010-2020-sample-1M") .unwrap() .unwrap(); // iterate over rows for _row in sheet.rows() {} } ``` -------------------------------- ### Hyperfine Benchmark Results Source: https://github.com/tafia/calamine/blob/master/README.md Displays the output of hyperfine benchmarks comparing the execution times of Calamine, Excelize, ClosedXML, and openpyxl for reading a large XLSX file. Results are from an AMD RYZEN 9 5900X on Windows 11. ```bash 0.22.1 calamine.exe Time (mean ± σ): 25.278 s ± 0.424 s [User: 24.852 s, System: 0.470 s] Range (min … max): 24.980 s … 26.369 s 10 runs v2.8.0 excelize.exe Time (mean ± σ): 44.254 s ± 0.574 s [User: 46.071 s, System: 7.754 s] Range (min … max): 42.947 s … 44.911 s 10 runs 0.102.1 closedxml.exe Time (mean ± σ): 178.343 s ± 3.673 s [User: 177.442 s, System: 2.612 s] Range (min … max): 173.232 s … 185.086 s 10 runs 3.0.10 openpyxl.py Time (mean ± σ): 238.554 s ± 1.062 s [User: 238.016 s, System: 0.661 s] Range (min … max): 236.798 s … 240.167 s 10 runs ``` -------------------------------- ### Open Typed Workbook from File Path (Rust) Source: https://context7.com/tafia/calamine/llms.txt Opens a spreadsheet file with a statically known format (Xlsx, Xls, Xlsb, or Ods) and returns the corresponding reader. The type must be explicitly annotated or inferred from context. Uses a BufReader internally. ```rust use calamine::{open_workbook, Reader, Xlsx, Data}; fn main() -> Result<(), Box> { // Open an xlsx file with an explicitly typed reader. let mut workbook: Xlsx<_> = open_workbook("tests/issues.xlsx")?; // List all sheet names in workbook order. println!("Sheets: {:?}", workbook.sheet_names()); // e.g. Sheets: ["Sheet1", "Sheet2"] // Read a specific worksheet by name. let range = workbook.worksheet_range("Sheet1")?; println!("Dimensions: {:?} rows x {:?} cols", range.height(), range.width()); // Iterate every row. for row in range.rows() { for cell in row { match cell { Data::Int(i) => print!("{i}\t"), Data::Float(f) => print!("{f:.2}\t"), Data::String(s) => print!("{s}\t"), Data::Bool(b) => print!("{b}\t"), Data::Empty => print!("\t"), other => print!("{other}\t"), } } println!(); } Ok(()) } ``` -------------------------------- ### Read and Iterate XLSX with ClosedXML (C#) Source: https://github.com/tafia/calamine/blob/master/README.md Illustrates opening an XLSX workbook and iterating over rows using the ClosedXML library in C#. Ensure the ClosedXML NuGet package is referenced. ```csharp using ClosedXML.Excel; internal class Program { private static void Main(string[] args) { // Open workbook using var workbook = new XLWorkbook("NYC_311_SR_2010-2020-sample-1M.xlsx"); // Get Worksheet // "NYC_311_SR_2010-2020-sample-1M" var worksheet = workbook.Worksheet(1); // Iterate over rows foreach (var row in worksheet.Rows()) { } } } ``` -------------------------------- ### Open Workbook from Read+Seek Stream (Rust) Source: https://context7.com/tafia/calamine/llms.txt Opens a workbook from an in-memory buffer or any type implementing Read + Seek + Clone, without touching the filesystem. Useful for processing spreadsheets received over a network or embedded in another file. ```rust use calamine::{open_workbook_auto_from_rs, Reader}; use std::io::Cursor; fn process_bytes(data: Vec) -> Result<(), Box> { // Wrap raw bytes in a seekable cursor. let cursor = Cursor::new(data); // Format is detected automatically by probing. let mut workbook = open_workbook_auto_from_rs(cursor)?; let range = workbook.worksheet_range_at(0) .ok_or("No sheets found")?; println!("First sheet has {} cells", range.cells().count()); Ok(()) } ``` -------------------------------- ### Read Spreadsheet with Header Row Source: https://github.com/tafia/calamine/blob/master/README.md Demonstrates how to specify a header row when reading a spreadsheet range. This is useful for accessing columns by name. Note performance implications for different file types. ```rust use calamine::{HeaderRow, Reader, Xlsx, open_workbook}; let mut excel: Xlsx<_> = open_workbook("file.xlsx").unwrap(); let sheet1 = excel .with_header_row(HeaderRow::Row(3)) .worksheet_range("Sheet1") .unwrap(); ``` -------------------------------- ### Convert Excel Cells to Chrono Types with `as_date`, `as_time`, `as_datetime`, `as_duration` Source: https://context7.com/tafia/calamine/llms.txt When the `chrono` feature is enabled, use these methods to convert `Data::DateTime`, `Data::DateTimeIso`, and `Data::DurationIso` cells into `chrono` types like `NaiveDate`, `NaiveTime`, `NaiveDateTime`, and `Duration`. Ensure `calamine` is added to `Cargo.toml` with the `chrono` feature. ```rust // Cargo.toml: calamine = { version = "0.34", features = ["chrono"] } use calamine::{open_workbook, Reader, Xlsx, DataType}; fn main() -> Result<(), Box> { let mut wb: Xlsx<_> = open_workbook("tests/date.xlsx")?; let range = wb.worksheet_range("Sheet1")?; for (row, col, cell) in range.used_cells() { if let Some(date) = cell.as_date() { println!("[{row},{col}] date: {date}"); // chrono::NaiveDate } if let Some(time) = cell.as_time() { println!("[{row},{col}] time: {time}"); // chrono::NaiveTime } if let Some(dt) = cell.as_datetime() { println!("[{row},{col}] datetime: {dt}"); // chrono::NaiveDateTime } if let Some(dur) = cell.as_duration() { println!("[{row},{col}] duration: {}s", dur.num_seconds()); // chrono::Duration } } Ok(()) } ``` -------------------------------- ### Open Workbook Automatically and Read Data Source: https://github.com/tafia/calamine/blob/master/README.md Use `open_workbook_auto` when the file type is unknown. This snippet shows how to read data from a specific worksheet, calculate total and non-empty cells, and verify cell counts. ```rust use calamine::{Reader, open_workbook_auto, Xlsx, DataType}; // opens a new workbook let path = ...; // we do not know the file type let mut workbook = open_workbook_auto(path).expect("Cannot open file"); // Read whole worksheet data and provide some statistics if let Some(Ok(range)) = workbook.worksheet_range("Sheet1") { let total_cells = range.get_size().0 * range.get_size().1; let non_empty_cells: usize = range.used_cells().count(); println!("Found {} cells in 'Sheet1', including {} non empty cells", total_cells, non_empty_cells); // alternatively, we can manually filter rows assert_eq!(non_empty_cells, range.rows() .flat_map(|r| r.iter().filter(|&c| c != &DataType::Empty)).count()); } ``` -------------------------------- ### Inspect Workbook Metadata and Read Data with Reader Trait Source: https://context7.com/tafia/calamine/llms.txt Demonstrates how to use the `Reader` trait to inspect sheet metadata (type, visibility) and read data, including formulas. Requires opening a workbook using `open_workbook` and specifying the file type. ```rust use calamine::{open_workbook, Reader, Xlsx, HeaderRow, SheetType, SheetVisible}; fn main() -> Result<(), Box> { let mut wb: Xlsx<_> = open_workbook("tests/issues.xlsx")?; // Inspect sheet metadata (type and visibility). for sheet in wb.sheets_metadata() { let typ = match sheet.typ { SheetType::WorkSheet => "worksheet", SheetType::ChartSheet => "chart", SheetType::MacroSheet => "macro", _ => "other", }; let vis = match sheet.visible { SheetVisible::Visible => "visible", SheetVisible::Hidden => "hidden", SheetVisible::VeryHidden => "very hidden", }; println!(" '{}' [{}] ({})", sheet.name, typ, vis); } // Set a custom header row (1-based row index) before reading. // For xlsx/xlsb this takes effect immediately (lazy loading). let range = wb .with_header_row(HeaderRow::Row(2)) .worksheet_range("Sheet1")?; // Access range boundaries in absolute (row, col) coordinates. println!("Start: {:?}, End: {:?}", range.start(), range.end()); // Read formulas alongside values. let formulas = wb.worksheet_formula("Sheet1")?; for (row, col, formula) in formulas.used_cells() { println!("Cell ({row},{col}): ={formula}"); } Ok(()) } ``` -------------------------------- ### Iterate and Check Cell Data Types with Calamine Source: https://context7.com/tafia/calamine/llms.txt Demonstrates iterating through a worksheet range, checking cell data types using predicates, and performing type coercions. It also shows pattern matching directly on the Data enum variants. ```rust use calamine::{open_workbook, Reader, Xlsx, Data, DataType}; fn main() -> Result<(), Box> { let mut wb: Xlsx<_> = open_workbook("tests/date.xlsx")?; let range = wb.worksheet_range("Sheet1")?; for (row, col, cell) in range.used_cells() { // Type predicates. if cell.is_int() { println!("[{{row}},{{col}}] int: {{}}", cell.get_int().unwrap()); } if cell.is_float() { println!("[{{row}},{{col}}] float: {{}}", cell.get_float().unwrap()); } if cell.is_string() { println!("[{{row}},{{col}}] string: {{}}", cell.get_string().unwrap()); } if cell.is_bool() { println!("[{{row}},{{col}}] bool: {{}}", cell.get_bool().unwrap()); } if cell.is_datetime() { println!("[{{row}},{{col}}] datetime serial: {{}}", cell.get_datetime().unwrap().as_f64()); } if cell.is_datetime_iso(){ println!("[{{row}},{{col}}] ISO datetime: {{}}", cell.get_datetime_iso().unwrap()); } if cell.is_duration_iso(){ println!("[{{row}},{{col}}] ISO duration: {{}}", cell.get_duration_iso().unwrap()); } if cell.is_error() { println!("[{{row}},{{col}}] error: {{}}", cell.get_error().unwrap()); } // Coercions (attempt conversion across types). if let Some(v) = cell.as_f64() { println!("[{{row}},{{col}}] as f64 = {{v}}"); } if let Some(v) = cell.as_i64() { println!("[{{row}},{{col}}] as i64 = {{v}}"); } if let Some(s) = cell.as_string() { println!("[{{row}},{{col}}] as string = {{s}}"); } } // Pattern matching directly on Data variants. for row in range.rows() { for cell in row { match cell { Data::Int(n) => println!("Int: {{n}}"), Data::Float(f) => println!("Float: {{f}}"), Data::String(s) => println!("String: {{s}}"), Data::Bool(b) => println!("Bool: {{b}}"), Data::DateTime(dt) => println!("DateTime serial: {{}}", dt.as_f64()), Data::DateTimeIso(s) => println!("DateTimeIso: {{s}}"), Data::DurationIso(s) => println!("DurationIso: {{s}}"), Data::Error(e) => println!("Error: {{e}}"), Data::Empty => {{}}, } } } Ok(()) } ``` -------------------------------- ### Access VBA Project and References Source: https://github.com/tafia/calamine/blob/master/README.md Checks for and extracts VBA project information, including module code and references. It iterates through references, reporting any that are broken or inaccessible. ```rust // Check if the workbook has a vba project if let Ok(Some(vba)) = workbook.vba_project() { let module1 = vba.get_module("Module 1").unwrap(); println!("Module 1 code:"); println!("{}", module1); for r in vba.get_references() { if r.is_missing() { println!("Reference {} is broken or not accessible", r.name); } } } ``` -------------------------------- ### Extracting VBA Project Code Source: https://context7.com/tafia/calamine/llms.txt Retrieve the VBA project from macro-enabled Excel files (.xlsm, .xlam, .xls). This allows inspection of module names, source code, and external library references. ```Rust use calamine::{open_workbook, Reader, Xlsx}; fn main() -> Result<(), Box> { let mut wb: Xlsx<_> = open_workbook("tests/vba.xlsm")?; if let Ok(Some(vba)) = wb.vba_project() { // List all module names. let names = vba.get_module_names(); println!("VBA modules: {:?}", names); // Read source code of a module. for name in &names { match vba.get_module(name) { Ok(code) => println!("---" {name} "---\n{code}"), Err(e) => eprintln!("Cannot read {name}: {e}"), } } // Inspect external references. for reference in vba.get_references() { println!("Reference: {} (libid: {})", reference.name, reference.libid); if reference.is_missing() { println!(" WARNING: reference is broken or inaccessible"); } } } else { println!("No VBA project found in workbook."); } Ok(()) } ``` -------------------------------- ### open_workbook Source: https://context7.com/tafia/calamine/llms.txt Opens a spreadsheet file with a statically known format (Xlsx, Xls, Xlsb, or Ods) and returns the corresponding reader. The type must be explicitly annotated or inferred from context. Uses a BufReader internally. ```APIDOC ## open_workbook — Open a typed workbook from a file path ### Description Opens a spreadsheet file with a statically known format (`Xlsx`, `Xls`, `Xlsb`, or `Ods`) and returns the corresponding reader. The type must be explicitly annotated or inferred from context. Uses a `BufReader` internally. ### Usage Example ```rust use calamine::{open_workbook, Reader, Xlsx, Data}; fn main() -> Result<(), Box> { // Open an xlsx file with an explicitly typed reader. let mut workbook: Xlsx<_> = open_workbook("tests/issues.xlsx")?; // List all sheet names in workbook order. println!("Sheets: {:?}", workbook.sheet_names()); // e.g. Sheets: ["Sheet1", "Sheet2"] // Read a specific worksheet by name. let range = workbook.worksheet_range("Sheet1")?; println!("Dimensions: {:?} rows x {:?} cols", range.height(), range.width()); // Iterate every row. for row in range.rows() { for cell in row { match cell { Data::Int(i) => print!("{i}\t"), Data::Float(f) => print!("{{f:.2}}\t"), Data::String(s) => print!("{s}\t"), Data::Bool(b) => print!("{b}\t"), Data::Empty => print!("\t"), other => print!("{{other}}\t"), } } println!(); } Ok(()) } ``` ``` -------------------------------- ### Shorthand Deserialization from Range with `Range::deserialize` Source: https://context7.com/tafia/calamine/llms.txt Use the `Range::deserialize` method as a shorthand for `RangeDeserializerBuilder::new().from_range()`. This method assumes the first row contains headers and uses all columns. ```rust use calamine::{open_workbook, Reader, Xlsx, Error}; use serde::Deserialize; #[derive(Debug, Deserialize)] struct Temperature { label: String, value: f64, } fn main() -> Result<(), Error> { let mut wb: Xlsx<_> = open_workbook("tests/temperature.xlsx")?; let range = wb.worksheet_range("Sheet1")?; // Directly call .deserialize() on the range. let mut iter = range.deserialize()?; let first: Temperature = iter.next().ok_or("empty range")?? ; assert_eq!(first.label, "celsius"); assert_eq!(first.value, 22.2222); println!("First record: {} = {}", first.label, first.value); Ok(()) } ``` -------------------------------- ### open_workbook_auto_from_rs Source: https://context7.com/tafia/calamine/llms.txt Opens a workbook from an in-memory buffer or any type implementing Read + Seek + Clone, without touching the filesystem. Useful for processing spreadsheets received over a network or embedded in another file. ```APIDOC ## open_workbook_auto_from_rs — Open a workbook from any `Read + Seek` stream ### Description Opens a workbook from an in-memory buffer or any type implementing `Read + Seek + Clone`, without touching the filesystem. Useful for processing spreadsheets received over a network or embedded in another file. ### Usage Example ```rust use calamine::{open_workbook_auto_from_rs, Reader}; use std::io::Cursor; fn process_bytes(data: Vec) -> Result<(), Box> { // Wrap raw bytes in a seekable cursor. let cursor = Cursor::new(data); // Format is detected automatically by probing. let mut workbook = open_workbook_auto_from_rs(cursor)?; let range = workbook.worksheet_range_at(0) .ok_or("No sheets found")?; println!("First sheet has {} cells", range.cells().count()); Ok(()) } ``` ``` -------------------------------- ### Handle Excel DateTimes Natively with Calamine Source: https://context7.com/tafia/calamine/llms.txt Shows how to use the ExcelDateTime struct to represent and convert Excel's serial date/time numbers. It covers decomposition into date/time components and optional conversion to chrono types. ```rust use calamine::{ExcelDateTime, ExcelDateTimeType}; fn main() { // Excel serial 45943.541 = 2025-10-13 12:59:02.400 let dt = ExcelDateTime::new(45943.541, ExcelDateTimeType::DateTime, false); // Without chrono: decompose to (year, month, day, hour, min, sec, milli). let (year, month, day, hour, min, sec, milli) = dt.to_ymd_hms_milli(); assert_eq!((year, month, day), (2025, 10, 13)); assert_eq!((hour, min, sec, milli), (12, 59, 2, 400)); println!("Date: {{year}}-{{month:02}}-{{day:02}} {{hour:02}}:{{min:02}}:{{sec:02}}.{{milli:03}}"); // Duration example (e.g. [hh]:mm:ss format). let dur = ExcelDateTime::new(1.5, ExcelDateTimeType::TimeDelta, false); println!("Is duration: {{}}", dur.is_duration()); // true println!("Duration as f64: {{}}", dur.as_f64()); // 1.5 // chrono conversion (requires `chrono` feature). #[cfg(feature = "chrono")] { if let Some(naive_dt) = dt.as_datetime() { println!("chrono NaiveDateTime: {{naive_dt}}"); } } } ``` -------------------------------- ### open_workbook_auto Source: https://context7.com/tafia/calamine/llms.txt Detects the file format from the file extension (or by brute-force probing when the extension is unknown) and returns a Sheets> enum. Use this when the file format is not known until runtime. ```APIDOC ## open_workbook_auto — Open a workbook with runtime format detection ### Description Detects the file format from the file extension (or by brute-force probing when the extension is unknown) and returns a `Sheets>` enum. Use this when the file format is not known until runtime. ### Usage Example ```rust use calamine::{open_workbook_auto, Reader, Data}; fn main() -> Result<(), Box> { // Works with .xls, .xlsx, .xlsm, .xlsb, .ods, or unknown extensions. let mut workbook = open_workbook_auto("path/to/spreadsheet.xlsx")?; // Access metadata: sheet names and defined names. for name in workbook.sheet_names() { println!("Sheet: {name}"); } for (name, formula) in workbook.defined_names() { println!("Defined name '{name}' = {formula}"); } // Iterate over all worksheets at once. for (sheet_name, range) in workbook.worksheets() { let (rows, cols) = range.get_size(); println!("Sheet '{sheet_name}': {rows} rows, {cols} cols"); let non_empty = range.used_cells().count(); println!(" Non-empty cells: {non_empty}"); } Ok(()) } ``` ``` -------------------------------- ### Deserialize Spreadsheet Range to Structs Source: https://github.com/tafia/calamine/blob/master/README.md Demonstrates deserializing a spreadsheet range into a struct with custom deserialization for potentially invalid float values. Requires Serde and Calamine. Use `deserialize_as_f64_or_none` for values that might not be floats. ```rust use calamine::{deserialize_as_f64_or_none, open_workbook, RangeDeserializerBuilder, Reader, Xlsx}; use serde::Deserialize; #[derive(Deserialize)] struct Record { metric: String, #[serde(deserialize_with = "deserialize_as_f64_or_none")] value: Option, } fn main() -> Result<(), Box> { let path = format!("{}/tests/excel.xlsx", env!("CARGO_MANIFEST_DIR")); let mut excel: Xlsx<_> = open_workbook(path)?; let range = excel .worksheet_range("Sheet1") .map_err(|_| calamine::Error::Msg("Cannot find Sheet1"))?; let iter_records = RangeDeserializerBuilder::with_headers(&["metric", "value"]).from_range(&range)?; for result in iter_records { let record: Record = result?; println!("metric={:?}, value={:?}", record.metric, record.value); } Ok(()) } ``` -------------------------------- ### Reading Excel Tables by Name Source: https://context7.com/tafia/calamine/llms.txt Explicitly load and access Excel Tables (structured references) by their names. Tables provide column headers and data ranges separately, and can be converted into a plain `Range`. ```Rust use calamine::{open_workbook, Error, Xlsx, Data}; fn main() -> Result<(), Error> { let mut wb: Xlsx<_> = open_workbook("tests/inventory-table.xlsx")?; // Tables are not loaded by default — must be called explicitly. wb.load_tables()?; // List all table names. for name in wb.table_names() { println!("Table: {name}"); } // Fetch a table by name. let table = wb.table_by_name("Table1")?; println!("Table: {}", table.name()); // "Table1" println!("Sheet: {}", table.sheet_name()); // "Sheet1" println!("Columns: {:?}", table.columns()); // ["Item", "Type", "Quantity"] // The data range excludes the header row. let data = table.data(); for (row, col, cell) in data.used_cells() { println!("[{row},{col}] = {cell}"); } // Convert table into a plain Range. let range: calamine::Range = wb.table_by_name("Table1")?.into(); println!("Range size: {:?}", range.get_size()); Ok(()) } ``` -------------------------------- ### Lenient Deserialization with Serde Source: https://context7.com/tafia/calamine/llms.txt Use these helper functions with Serde's `#[serde(deserialize_with = "...")]` attribute to handle cells with unexpected data types. They return `Option` or `Result` to prevent deserialization failures. ```Rust use calamine::{ open_workbook, Reader, Xlsx, RangeDeserializerBuilder, Error, deserialize_as_f64_or_none, deserialize_as_f64_or_string, deserialize_as_i64_or_none, deserialize_as_i64_or_string, }; use serde::Deserialize; #[derive(Debug, Deserialize)] struct Row { label: String, /// Yields None if the cell is not numeric. #[serde(deserialize_with = "deserialize_as_f64_or_none")] amount: Option, /// Yields Ok(i64) or Err(original_string). #[serde(deserialize_with = "deserialize_as_i64_or_string")] count: Result, } // With chrono feature: // deserialize_as_date_or_none, deserialize_as_date_or_string // deserialize_as_time_or_none, deserialize_as_time_or_string // deserialize_as_datetime_or_none, deserialize_as_datetime_or_string // deserialize_as_duration_or_none, deserialize_as_duration_or_string fn main() -> Result<(), Error> { let mut wb: Xlsx<_> = open_workbook("tests/issues.xlsx")?; let range = wb.worksheet_range("Sheet1")?; let iter = RangeDeserializerBuilder::new().from_range::<_, Row>(&range)?; for result in iter { match result { Ok(row) => println!("{:?}", row), Err(e) => eprintln!("Deserialization error: {e}"), } } Ok(()) } ``` -------------------------------- ### Retrieve Defined Names and Formulas Source: https://github.com/tafia/calamine/blob/master/README.md Retrieves and prints the defined names within a workbook along with their associated formulas. It also iterates through all sheets to count the number of formulas present in each. ```rust // You can also get defined names definition (string representation only) for name in workbook.defined_names() { println!("name: {}, formula: {}", name.0, name.1); } // Now get all formula! let sheets = workbook.sheet_names().to_owned(); for s in sheets { println!("found {} formula in '{}'", workbook .worksheet_formula(&s) .expect("sheet not found") .expect("error while getting formula") .rows().flat_map(|r| r.iter().filter(|f| !f.is_empty())) .count(), s); } ``` -------------------------------- ### Manipulate Worksheet Data with Range Source: https://context7.com/tafia/calamine/llms.txt Shows how to use the `Range` struct to access and manipulate rectangular worksheet data. Supports absolute and relative coordinate lookups, iteration over rows and cells, and building sub-ranges. ```rust use calamine::{open_workbook, Reader, Xlsx, Data, Cell, Range}; fn main() -> Result<(), Box> { let mut wb: Xlsx<_> = open_workbook("tests/issues.xlsx")?; let range = wb.worksheet_range("Sheet1")?; // Dimensions. println!("Size: {:?}", range.get_size()); // (height, width) println!("Start: {:?}", range.start()); // absolute (row, col) println!("End: {:?}", range.end()); // absolute (row, col) // Absolute lookup — coordinates relative to A1=(0,0). if let Some(cell) = range.get_value((0, 0)) { println!("A1 = {cell}"); } // Relative lookup — coordinates relative to range start. if let Some(cell) = range.get((0, 0)) { println!("Top-left of range = {cell}"); } // Row iteration. for (r, row) in range.rows().enumerate() { for (c, cell) in row.iter().enumerate() { if !cell.is_empty() { println!(" [{r},{c}] = {cell}"); } } } // Only non-empty cells. for (row, col, cell) in range.used_cells() { println!(" used [{row},{col}] = {cell}"); } // Extract the first row as header strings. if let Some(headers) = range.headers() { println!("Headers: {headers:?}"); } // Build a sub-range with absolute bounds. let sub = range.range((0, 0), (4, 2)); println!("Sub-range size: {:?}", sub.get_size()); // Build a range from sparse cells (e.g., when constructing test data). let cells = vec![ Cell::new((0, 0), Data::String("name".into())), Cell::new((0, 1), Data::String("score".into())), Cell::new((1, 0), Data::String("Alice".into())), Cell::new((1, 1), Data::Float(98.5)), ]; let custom_range = Range::from_sparse(cells); println!("Custom range: {}x{}", custom_range.height(), custom_range.width()); Ok(()) } ``` -------------------------------- ### Deserialize Excel Range to Rust Types with `RangeDeserializerBuilder` Source: https://context7.com/tafia/calamine/llms.txt Use `RangeDeserializerBuilder` to deserialize worksheet rows into Rust types via Serde. Supports custom header selection, headerless mode, and inferring headers from struct field names. The first row is treated as a header by default. ```rust use calamine::{open_workbook, Reader, Xlsx, RangeDeserializerBuilder, Error, deserialize_as_f64_or_none}; use serde::Deserialize; #[derive(Debug, Deserialize)] struct Record { name: String, #[serde(deserialize_with = "deserialize_as_f64_or_none")] score: Option, passed: bool, } fn main() -> Result<(), Error> { let mut wb: Xlsx<_> = open_workbook("tests/issues.xlsx")?; let range = wb.worksheet_range("Sheet1")?; // --- Mode 1: all headers inferred from first row --- let iter = RangeDeserializerBuilder::new().from_range::<_, Record>(&range)?; for result in iter { let rec: Record = result?; println!("{:?}", rec); } // --- Mode 2: select and reorder specific columns --- let iter = RangeDeserializerBuilder::with_headers(&["score", "name"]) .from_range::<_, (f64, String)>(&range)?; for result in iter { let (score, name) = result?; println!("{name}: {score}"); } // --- Mode 3: headers inferred from struct field names --- let iter = RangeDeserializerBuilder::with_deserialize_headers::() .from_range(&range)?; for result in iter { let rec: Record = result?; println!("{:?}", rec); } // --- Mode 4: no header row, raw Vec per row --- use calamine::Data; let iter = RangeDeserializerBuilder::new() .has_headers(false) .from_range::<_, Vec>(&range)?; for row in iter { println!("{:?}", row?); } Ok(()) } ``` -------------------------------- ### Handling Errors with `calamine::Error` Source: https://context7.com/tafia/calamine/llms.txt The `calamine::Error` type wraps various specific errors including format errors (XlsxError, XlsError, etc.), IO errors, and deserialization errors. The `safe_read` function demonstrates mapping errors using `map_err`. The `main` function shows a `match` statement for handling different error variants. ```rust use calamine::{open_workbook_auto, Reader, Error}; fn safe_read(path: &str) -> Result<(), Error> { let mut wb = open_workbook_auto(path)?; let range = wb.worksheet_range("Sheet1").map_err(|e| { eprintln!("Failed to read sheet: {e}"); e })?; println!("Loaded {} rows.", range.height()); Ok(()) } ``` ```rust fn main() { match safe_read("data.xlsx") { Ok(()) => println!("Done."), Err(Error::Io(e)) => eprintln!("IO error: {e}"), Err(Error::Xlsx(e)) => eprintln!("XLSX error: {e}"), Err(Error::Xls(e)) => eprintln!("XLS error: {e}"), Err(Error::Ods(e)) => eprintln!("ODS error: {e}"), Err(Error::De(e)) => eprintln!("Deserialize error: {e}"), Err(e) => eprintln!("Error: {e}"), } } ``` -------------------------------- ### Zero-Copy Worksheet Access with ReaderRef Trait Source: https://context7.com/tafia/calamine/llms.txt Utilizes the `ReaderRef` trait for efficient, zero-copy access to worksheet data in XLSX and XLSB files. This method borrows shared strings directly from the workbook, reducing memory allocations. ```rust use calamine::{open_workbook, ReaderRef, Xlsx, DataType}; fn main() -> Result<(), Box> { let mut wb: Xlsx<_> = open_workbook("tests/issues.xlsx")?; // Borrow strings; no allocation for shared string values. let range = wb.worksheet_range_ref("Sheet1")?; let string_cells: Vec<&str> = range .used_cells() .filter_map(|(_, _, cell)| cell.get_string()) .collect(); println!("String values (borrowed): {:?}", string_cells); Ok(()) } ``` -------------------------------- ### Range - Rectangular Worksheet Data Grid Source: https://context7.com/tafia/calamine/llms.txt The `Range` struct is the primary data container for worksheet data. It represents a rectangular grid of cells and supports access via absolute (spreadsheet-style) and relative (0-indexed) coordinates. It provides methods for inspecting dimensions, retrieving cell values, iterating over rows and used cells, and extracting headers. ```APIDOC ## `Range` — Rectangular worksheet data grid `Range` is the central data container returned by `worksheet_range`. It stores cells in row-major order and supports both absolute (spreadsheet-style) and relative (0-indexed) coordinate access. ### Methods - **`get_size()`**: Returns the dimensions (height, width) of the range. - **`start()`**: Returns the absolute (row, col) coordinates of the top-left cell of the range. - **`end()`**: Returns the absolute (row, col) coordinates of the bottom-right cell of the range. - **`get_value(coord)`**: Retrieves the cell value at the given absolute (row, col) coordinates. - **`get(coord)`**: Retrieves the cell value at the given relative (row, col) coordinates within the range. - **`rows()`**: Returns an iterator over the rows of the range. - **`used_cells()`**: Returns an iterator over the non-empty cells in the range, yielding (row, col, cell) tuples. - **`headers()`**: Extracts and returns the first row of the range as a header. - **`range(start_coord, end_coord)`**: Creates a new `Range` representing a sub-section of the current range, defined by start and end coordinates. - **`height()`**: Returns the height of the range. - **`width()`**: Returns the width of the range. ### Associated Functions - **`Range::from_sparse(cells)`**: Constructs a `Range` from a vector of `Cell` objects, useful for creating ranges from sparse data. ```