A lightweight, dependency-free .NET library for reading Excel workbooks (.xlsx).
using var workbook = Workbook.Open("data.xlsx");
var value = workbook.Sheet("Sheet1")?.Cell("B2")?.Value;using var workbook = Workbook.Open("Book1.xlsx");
var sheet = workbook.Sheet("Sheet1");
// Access by cell address
var cell = sheet?.Cell("A1");
Console.WriteLine(cell?.Value);
// Or by row and column index (1-based)
var value = sheet?.Cell(2, 3)?.Value;
// Get a specific row or column
var row = sheet?.Row(5);
var column = sheet?.Column(2);
// Access cells from a row or column
var cellsInRow = row?.Cells;
var cellsInColumn = column?.Cells;
// Navigate up the hierarchy
var parentSheet = row?.Sheet;
var parentWorkbook = cell?.Row.Sheet.Workbook;using var workbook = Workbook.Open("report.xlsx");
foreach (var sheet in workbook.Sheets)
{
Console.WriteLine($"Sheet: {sheet.Name}");
foreach (var row in sheet.Rows)
{
foreach (var cell in row.Cells)
{
Console.Write($"{cell.Value}\t");
}
Console.WriteLine();
}
}All collections (Sheets, Rows, Columns, Cells) are IEnumerable<T>, so you can use LINQ:
// Find non-empty cells
var nonEmpty = sheet.Rows
.SelectMany(r => r.Cells)
.Where(c => !string.IsNullOrEmpty(c.Value));
// Get unique values from a column
var uniqueValues = sheet.Column(1)?.Cells
.Select(c => c.Value)
.Distinct();Handle common exceptions when opening workbooks:
try
{
using var workbook = Workbook.Open("data.xlsx");
// Work with the workbook
}
catch (FileNotFoundException ex)
{
Console.WriteLine($"File not found: {ex.FileName}");
}
catch (IOException ex)
{
Console.WriteLine($"Error reading file: {ex.Message}");
}Including hidden elements
By default, hidden sheets, rows, and columns are excluded. Use WorkbookOptions to include them:
using var workbook = Workbook.Open("data.xlsx", new WorkbookOptions { IncludeHidden = true });
// Now hidden sheets, rows, and columns are accessible
var hiddenSheet = workbook.Sheet("HiddenSheet");For large workbooks, you can defer loading sheet data until needed:
using var workbook = Workbook.Open("large-file.xlsx", new WorkbookOptions { LoadSheets = false });
// Sheet metadata is available, but rows/cells are not yet loaded
var sheet = workbook.Sheet("Sheet1");
// Load the sheet data when needed
sheet?.Open();For workbooks with many sheets, enable parallel loading for better performance:
using var workbook = Workbook.Open("many-sheets.xlsx", new WorkbookOptions { ParallelLoadSheets = true });
// All sheets are loaded concurrently
foreach (var sheet in workbook.Sheets)
{
Console.WriteLine($"{sheet.Name}: {sheet.Rows.Count()} rows");
}Load workbooks directly from any stream (useful for web uploads, embedded resources, etc.):
// From a file stream
using var stream = File.OpenRead("data.xlsx");
using var workbook = Workbook.Open(stream);
// From a memory stream (e.g., downloaded content)
var bytes = await httpClient.GetByteArrayAsync(url);
using var memoryStream = new MemoryStream(bytes);
using var workbook = Workbook.Open(memoryStream);Dates and times are automatically converted from Excel's internal numeric format to ISO format strings:
var cell = sheet?.Cell("A1");
Console.WriteLine(cell?.Value); // Output: 2025-12-31The Cell.Format property indicates the number format category, which is useful for custom parsing of other formats:
var cell = sheet?.Cell("B2");
var value = cell?.Format switch
{
NumberFormat.Percentage => double.Parse(cell.Value.TrimEnd('%')) / 100,
NumberFormat.Currency => decimal.Parse(cell.Value, NumberStyles.Currency),
NumberFormat.Number => double.Parse(cell.Value),
_ => null as double?
};Format categories include General, Number, Currency, Accounting, Date, Time, Percentage, Fraction, Scientific, Text, Special, Custom, and Unsupported.
- Zero dependencies — Uses only built-in .NET APIs
- Stream support — Load from files, memory streams, or any readable stream
- LINQ-friendly — Collections like
Sheets,Rows, andCellsareIEnumerable<T> - Visibility-aware — Respects hidden sheets, rows, and columns by default
- Lazy loading — Optionally defer sheet loading for better performance
- Parallel loading — Load multiple sheets concurrently for large workbooks
- Well-tested — Comprehensive test suite with 99 unit tests
| Class | Description |
|---|---|
Workbook |
Represents an Excel file; provides access to sheets and metadata |
Sheet |
A worksheet containing rows, columns, and cells |
Row |
A row with access to its cells |
Column |
A column with access to its cells |
Cell |
A single cell with its value and format |
WorkbookOptions |
Configuration for loading workbooks |
This library focuses on reading Excel files. The following are out of scope:
- File formats other than
.xlsx - Writing/modifying workbooks
- Formula evaluation
- Cell formatting/styles
- .NET 8.0 or later
MIT
An older version of this library has been published on NuGet without my authorization. I am currently working on publishing this new much improved version as an official NuGet package. Any NuGet package not explicitly linked or mentioned in this repository should be considered unofficial. Further updates regarding an official package will be announced here.