Excel-PRIME
4.2601.31-Alpha
Use the latest V4 package
See the version list below for details.
dotnet add package Excel-PRIME --version 4.2601.31-Alpha
NuGet\Install-Package Excel-PRIME -Version 4.2601.31-Alpha
<PackageReference Include="Excel-PRIME" Version="4.2601.31-Alpha" />
<PackageVersion Include="Excel-PRIME" Version="4.2601.31-Alpha" />
<PackageReference Include="Excel-PRIME" />
paket add Excel-PRIME --version 4.2601.31-Alpha
#r "nuget: Excel-PRIME, 4.2601.31-Alpha"
#:package Excel-PRIME@4.2601.31-Alpha
#addin nuget:?package=Excel-PRIME&version=4.2601.31-Alpha&prerelease
#tool nuget:?package=Excel-PRIME&version=4.2601.31-Alpha&prerelease
Excel_PRIME 🌟
- Excel_Performant Reader via Interfaces for Memory Efficiency.
- Without using any external libraries.
- Optimised for Range extraction.
What does that mean?
- Yet another Excel reader ?,
- Starting with .Net 8 as the performant Runtime (See Benchmarks)
- .Net9 gives an extra 5% boost,
- .Net10 Another 5% over .Net9 😉
Lets take each of the above elements and explain:
Excel 📈
- Open Large 2007 (Onwards) XLSX file formats and XLSB in V3.##
- Zip Deflate format Only
Performant 🚀
- Try to be as fast as possible, i.e.
- Forward only Lazy loading
- Only "Quick" decipher / convert of the cell(s) types to ease GC pressure
- No attempt at "creating / using" datatables with headers etc.
- Use
IEnumerables with initial offset starts (Row / Column) - Allow
CancellationTokens to be used to allow page transitioning cancellation (More on this later)
- Now the fastest in Real world usage 2025-11-19 onwards
- Strongly-typed accessors (
AsInt32,AsDateTime, etc)
Q & A's
- Q: There are others that are faster
- A: Agreed, but then
- They do not have range extraction.
- Or
optionallyallow the use of the OS's TempFile System to store massive sheets - Or re-use of already extracted (massive) sheets
- Or allow multiple sheets to be read at the same time
- because others use global memory to represent the current row
- Or have a single access into the Zip Excel file
Reader 📋
- Read only
- Therefore no calculations or updates to formula calls
Interfaces 🏗️
- Will use the DotNet core functionality by default
- But, if your target deployment allows for the use of native performant binaries, then via the use of interfaces these will be pluggable
- i.e. Using
Zlib.Netfor getting the data streams out of the compressed Excel file faster. (OrSharpZipLib/PowerPlayZipper) - A faster / slimmer implementation for xml stream reading (i.e. TurboXml)
- i.e. Using
- Allow the implementation of different source files (i.e. XLSB)
Q & A's
- Q: Why?
- A: As mentioned above, this is to allow a developer to replace with external nugets that might perform better XML speed etc.
Memory 🌐
- The reason for this project, is to handle very large XSLX files (i.e. > 500K rows with > 180 columns per sheet, with multiple sheets of this size)
- For
ETLvalidation scenarios, i.e. make sure that the user modified data that has been transferred has interaction rules applied, before moving onto theTandLstages - Try not to hit / store in the LOH
- No internal .Net memory of previously loaded sheets / rows.
Q & A's
- Q: It appears that this uses more memory than other implementations
- A: Currently yes, but it is being optimised for
Range Extraction,- AND for allowing multiple rows (With cell data) to be stored in memory at the same time, (i.e. via
ToList()call); - AND to allow multiple sheets to be read at the same time (Unlike some to of the others that use "a single" global memory to represent a row)
- And it appears that the current benchmarks do not extract unless a
ToStringand a check on the result is used (Otherwise the Jit removes the unassigned dead code) - And, the memory used will actually be used in the ETL pipeline anyway, so it's just being truthful
- AND for allowing multiple rows (With cell data) to be stored in memory at the same time, (i.e. via
Efficiency 📦
- As hinted by the above statements, this is to be targetted at memory restricted environments (i.e. ASP Net VM's)
- Use the OS's
Temp Filecaching, so if the memory is tight then the Owner app will not have to worry about OOM exceptions, or having to use Swap Disk speeds. - Only unzip the sheet(s) when they are asked for
- Only load the shared strings upto the current request number
Q & A's
- Q: Sometimes the
Asyncawait s add too much overhead - A: true, that is why there are also the equivalent base interfaces that perform the same functionality without the need for the
async awaitoverheads, and still withConcellationTokenusage(s).
Etc. 🔧
CancellationTokens
- This is to allow the Large files to be Aborted
- Make "Most" of the "Net Cores'" API's Asynchronous
Tasks
IDisposable
- Got to tidy up those
Temp Files, and release theFileStream's
Caveats ⛔:
Not Be: Same sheet Thread safe 📊
- It will Not be same sheet Instance thread safe, because the xml reader will be locked (Forward only) to the sheet in use.
- but you can Open the sheet more than once, and have different threads running over it,
- And you can have Parallel threads access the Excel file
- Just remember to set
Options{ AccessExcelFileInForwardOnlyMode = false}
Not Do: Dynamic Ranges ⚠️
- i.e. Ones that contain formulas:
<definedName name="Prices">OFFSET(Sheet1!$A$1,0,0,COUNTA(Sheet1!$A:$A),1)</definedName>
Not Do: Poco 🤖
- A POCO / Type populator (Extensions can be written for that later)
Not Be a: Writer / Modifier 📚
- Totally beyond the scope of this project remit
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 5.2606.20 | 98 | 6/20/2026 | |
| 5.2606.7-Beta | 172 | 6/7/2026 | |
| 4.2605.17 | 113 | 5/17/2026 | |
| 4.2605.5 | 138 | 5/5/2026 | |
| 4.2604.28-RC3 | 127 | 4/28/2026 | |
| 4.2604.22-RC2 | 148 | 4/22/2026 | |
| 4.2604.16-RC1 | 146 | 4/16/2026 | |
| 4.2604.10-Beta | 146 | 4/10/2026 | |
| 4.2604.5-Beta | 122 | 4/5/2026 | |
| 4.2604.5-Alpha | 130 | 4/5/2026 | |
| 4.2601.31-Alpha | 252 | 1/31/2026 | |
| 4.2601.18-Alpha | 195 | 1/18/2026 | |
| 3.2601.16 | 153 | 1/16/2026 | |
| 3.2601.11 | 131 | 1/11/2026 | |
| 3.2601.4-XLSB-RC1 | 134 | 1/4/2026 | |
| 3.2601.2-XLSB-Beta | 133 | 1/2/2026 | |
| 3.2512.21-XLSB-Beta | 222 | 12/21/2025 | |
| 2.2512.14 | 189 | 12/14/2025 |
# 2026-01-## - V4 - Alpha
- ⛓️💥 **Breaking Change(s)**
- Removal of `GetSheetFileName(int offsetSheetId);`
- Removal of `GetDefinedRange` via `int sheetId`
- Removal of `Index` property from `ISheet`
- Internal Creation of WorkBooks
- Internal implementation of `IOpenXmlWorkBookReader::GetSheetNames` now returns the relative path to the sheetName
- `CellValue` is now a `class`, therefore no need to use `.Value`
- `ICell.CellValue` is now nullable
- Re-introduce the CellConversion for the XLSX cell types
- Use `ValueTask` and reduce memory allocations in some hot paths
- Cell object type 📅
- "Best Effort" `Operator` based conversion
- TryGet`Type` will return `out type`, if stored as that type.
- Add `Ecma376StandardProvider`
- Add `StylesExtractor`
- Attempt to make use of the Cell types
- Tinker with some `MethodImpl`
- Add `_iStyleRef` and start to add formatting based on it
- Fix fallout from making `CellValue` is now a `class`
- 🚀 [2026-01-31](https://github.com/Smurf-IV/Excel_PRIME/blob/main/Performance.md##2026-01-31-v4-alpha)
# 2026-01-16 - V3
- Remove some `AggressiveOptimization` and allow `i-cache` to do its job
- Implement "Hot-Paths" for cell type access
- Reduce some memory allocations for ReadOnly CellCollections
- [2026-01-16](https://github.com/Smurf-IV/Excel_PRIME/blob/main/Performance.md#2026-01-16)
# 2026-01-11 - V3
- Add XLS**B** 💾 (BIFF12)
- ⛓️💥 **Breaking Change(s)**
- `FileType` has been removed, and Open via the Public class type
- `IXmlReaderHelpers` has become `IOpenXmlReaderHelpers`, with slightly different methods
- `IXmlWorkBookReader` has become `IOpenXmlWorkBookReader`
- `IXmlSheetReader` has become `IOpenXmlSheetReader`
- Removal of the Conversion options `Number###`
- Changed `GetAllCells` to return `IReadOnlyList<ICell?>?`
- Watch out for those null rows !
- 🚀 Big Performance improvements [2026-01-11](https://github.com/Smurf-IV/Excel_PRIME/blob/main/Performance.md#2026-01-11)
# 2025-12-14 - V2
- ⛓️💥 **Breaking Change** 🔩
- The Async classes now have `Async` appended to be distinct from the non async versions
- But, `Async` inherit from the non, so they are interchangable
- Implement [GetUserRange(...)](https://github.com/Smurf-IV/Excel_PRIME/issues/7)
- [Range Performance on 2025-12-14](https://github.com/Smurf-IV/Excel_PRIME/blob/main/Performance.md#2025-12-14)
- User defined, using the `"A1:B10"` or `"$A$1:$B$10"` syntax
- [Range Performance on 2025-12-10](https://github.com/Smurf-IV/Excel_PRIME/blob/main/Performance.md#2025-12-10)
- Improve _memory usage_(s) 🧑💻
- Make `DefinedName`'s work with `localSheetId`definitions
- Benchmarks for range extraction
- Add `IEnumerable`s _All_ the way down ⤵️
- i.e. remove the need for Asynchronous awaits
- 🚀 Yielding More Performance improvements
- [Performance on 2025-11-16](https://github.com/Smurf-IV/Excel_PRIME/blob/main/Performance.md#2025-11-16)
- Read `definedName`s (Ranges / Cell / Value / Dynamic) 📇
- Implement RangeExtraction
- Global rangeNames
- Deal with blank rows in a sheet 🗋
- Return a `null` cell row
- Deal with Empty cells in a row 🗅
- Return a `null` cell
- Remove some warnings