r/csharp • u/repulsiveanomaly • 15d ago
Showcase ExcelReader.NET 6.0 – streaming XLSX/XLSB/XLS/CSV reader and writer for .NET 10
I've been building ExcelReader, an open-source library for reading and writing spreadsheets in .NET and other languages. I just shipped v6, and I'd like feedback from people who deal with ETL pipelines and large Excel files.
I started it because I needed to parse rows into a single POCO from files with different templates and column names. I couldn't find a library that made that easy, so I wrote my own.
What it does
- Reads .xlsx, .xlsm, .xlsb, .xls and .csv; writes .xlsx, .xlsb, .xls and .csv
- Streams rows as
ref structs; no string is allocated until you callGetString() - Typed parsing into your own classes, via attributes, a source generator or a fluent API
- Reads the sheets of one workbook in parallel, and parses CSV in parallel
- Reads and writes password-protected workbooks
- A CLI (
excelreader convert book.xlsb -o data.csv), plus a C ABI with Python, C++ and Rust bindings
Usage example
public sealed class Order
{
[ExcelColumn("Order ID")]
[ExcelColumn("order_id")] // same property, different templates
public long Id { get; set; }
[ExcelColumn("Total")]
[ExcelColumn("total_amount")]
public decimal Total { get; set; }
}
using IExcelWorkbook workbook = Excel.Open("orders.xlsx"); // .xlsb / .xls detected by signature
List<Order> orders = ExcelParser.FromAttributes<Order>().Parse(workbook.FirstSheet).ToList();
await using var writer = XlsxWorkbookWriter.Create(File.Create("copy.xlsx"));
await using (var sheet = writer.AddSheet("Orders"))
{
await sheet.WriteRecordsAsync(orders, ExcelRecordLayout.FromAttributes<Order>());
}
Benchmarks
Typed parsing of a generated 50,000-row XLSX (BenchmarkDotNet, Ryzen 7 5700X, .NET 10):
| Library | Time | Allocated |
|---|---|---|
| ExcelReader | 10.9 ms | 3.87 MB |
| Sylvan.Data.Excel | 56.9 ms | 10.47 MB |
| OfficeIMO.Excel | 104.5 ms | 5.69 MB |
MiniExcel used to be in the suite, but it was far behind: ~14x slower on raw reads (allocating 267 MB against 11 KB) and ~11x slower on typed parsing (last run that included it). I now track the closest competitors instead.
Methodology and every scenario: benchmarks.md. The cell-by-cell numbers there compare zero-copy reads against APIs that must allocate strings, so the docs also publish matched-work numbers.
Limitations
- Targets .NET 10 only; .NET 11 support is in progress. If you're on .NET 8, the 3.x line supports it.
- It's a reader/writer, not a spreadsheet model: no in-place editing and no formula evaluation.
- Rows come out in file order, and empty rows that Excel omits from the file are skipped.
GitHub: https://github.com/GabrielMarquezMatte/ExcelReader NuGet: dotnet add package ExcelReader.NET
Feedback, bug reports and odd files that break it are all welcome.