# Spreadsheet
<!-- MDOC !-->
A fast, memory-efficient Elixir library for parsing spreadsheet files powered by Rust and [Calamine](https://docs.rs/calamine/latest/calamine/).
## Features
- 🚀 **Fast Performance** - Native Rust implementation via NIFs for high-speed parsing
- 📁 **Multiple Formats** - Supports .xls, .xla, .xlsx, .xlsm, .xlam, .xlsb, and .ods files
- 💾 **Memory Efficient** - Parse from file paths or binary content
- 🗂️ **Sheet Management** - List and filter sheet names, including hidden sheets
- 📅 **Smart Type Handling** - Automatic conversion of dates to NaiveDateTime and numbers to Float
- 🔧 **Simple API** - Clean, functional interface with {:ok, result} | {:error, reason} patterns
## Usage
### Getting Sheet Names
List all sheet names in a file:
```elixir
iex> Spreadsheet.sheet_names("financial_data.xlsx")
{:ok, ["Q1 Revenue", "Q2 Revenue", "Summary"]}
```
Or from binary content:
```elixir
iex> content = File.read!("financial_data.xlsx")
iex> Spreadsheet.sheet_names_from_binary(content)
{:ok, ["Q1 Revenue", "Q2 Revenue", "Summary"]}
```
### Filtering Hidden Sheets
Exclude hidden sheets from the results:
```elixir
iex> Spreadsheet.sheet_names("workbook.xlsx", hidden: false)
{:ok, ["Visible Sheet"]}
```
### Parsing Sheet Data
Parse a specific sheet by name:
```elixir
iex> Spreadsheet.parse("sales.xlsx", "Q1 Data")
{:ok, [
["Product", "Sales", "Date"],
["Widget A", 1500.0, ~N[2024-01-15 00:00:00]],
["Widget B", 2300.0, ~N[2024-01-20 00:00:00]]
]}
```
Or from binary content:
```elixir
iex> content = File.read!("sales.xlsx")
iex> Spreadsheet.parse_from_binary(content, "Q1 Data")
{:ok, [
["Product", "Sales", "Date"],
["Widget A", 1500.0, ~N[2024-01-15 00:00:00]],
["Widget B", 2300.0, ~N[2024-01-20 00:00:00]]
]}
```
### Data Type Handling
The library automatically converts data types:
- **Dates**: Converted to `NaiveDateTime` structs
- **Numbers**: Converted to `Float` values
- **Empty cells**: Returned as `nil`
- **Text**: Returned as strings
For detailed information on the underlying parsing engine, see the [Calamine documentation](https://docs.rs/calamine/latest/calamine/).
<!-- MDOC !-->
## Installation
Add `spreadsheet` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:spreadsheet, "~> 0.2.0"}
]
end
```
### No Rust Installation Required
By default, the library uses precompiled NIFs, so **you don't need Rust installed**. If you want to force compilation from source, set the application environment:
```elixir
config :rustler_precompiled, :force_build, spreadsheet: true
```
## Performance
ExSpreadsheet is built for performance and handles large files efficiently:
- **Native Speed**: Rust-powered parsing for maximum throughput
- **Memory Efficient**: Streaming approach minimizes memory usage
- **Cross-Platform**: Precompiled NIFs for major platforms (Linux, macOS, Windows)
- **Production Ready**: Battle-tested in high-volume data processing environments
## Why Spreadsheet?
Compared to other Elixir spreadsheet libraries:
- **Faster**: Native Rust implementation outperforms pure Elixir parsers
- **More Formats**: Supports more file formats including .ods and legacy .xls files
- **Better Memory Usage**: Efficient memory handling for large files
- **Zero Setup**: No need to install external dependencies
### Alternatives
- [XlsxReader](https://hex.pm/packages/xlsx_reader) - Pure Elixir, XLSX only
- [Xlsxir](https://hex.pm/packages/xlsxir) - XML-based parsing, XLSX only
## Development
### Publishing a new version
Follow the [rustler_precompiled guide](https://hexdocs.pm/rustler_precompiled/precompilation_guide.html):
1. Release a new tag
2. Push the code with the new tag: `git push origin main --tags`
3. Wait for all NIFs to be built
4. Download precompiled NIFs: `mix rustler_precompiled.download Spreadsheet.Calamine --all`
5. Release the package to Hex.pm
## Copyright and License
Copyright (c) 2025 Wilhelm H Kirschbaum
This work is free. You can redistribute it and/or modify it under the
terms of the MIT License. See the [LICENSE.md](./LICENSE.md) file for more details.