Releases: GabrielMarquezMatte/ExcelReader
Release list
v3.1.0
What's Changed
Added
-
Batch-at-a-time reads across the C ABI and all three bindings — a sheet no longer has
to be materialized in one call, so peak memory is one batch instead of one sheet. New
exports:xl_typed_reader_open/xl_typed_reader_next/xl_typed_reader_closefor typed
reads, andxl_parse_arrow_streamover the Arrow C stream interface.- Python:
Workbook.iter_parse_typed,to_record_batch_reader, plusiter_pandasand
iter_polars. - C++:
xl::typed_reader<T>andxl::arrow_stream<T>. - Rust:
Workbook::typed_chunksandarrow::parse_arrow_stream(behind thearrow
feature).
The .NET reader already streams row-by-row by construction and is unchanged. Each
binding's README documents the semantics: one chunked read per workbook, what
batch_sizemeans, and what invalidates a live reader. - Python:
-
find_package(excelreader)for the C++ package —cmake --installnow installs the
headers, the native binary and a config package, so a downstream project can consume an
install prefix instead of vendoring the repo. The existingFetchContentroute is
unchanged, and the install rules stay off whencppis pulled in as a subproject. -
Shared column style and width validation across the XLSX, XLSB and XLS sheet writers, so
an invalid column definition is rejected the same way in all three.
Fixed
- A second chunked read on the same workbook is now rejected instead of producing undefined
results, andxl_typed_reader_openzeroes*out_readeron every failure path — a caller
that checks the out-param rather than the return code can no longer read a stale pointer. - Guards against double-buffered batches and against use of an already-released Arrow
stream; the Arrow stream's release, error and schema contracts were tightened to match
what the C Data Interface requires. OpenTransientfault ordering, and several inaccuracies in the native C header.- Agile encryption: the CBC path now verifies the transform consumed the whole segment
instead of silently accepting a short read. - Python:
iter_pandasgot its own pyarrow guard, andsplit_blocksis pinned so the
pandas conversion no longer depends on a pyarrow default that can change.
Performance
- Agile package encryption reuses one CBC transform across segments instead of rebuilding
it per segment. xl_parse_arrownow routes through the same resumable session as the chunked path, with
its memory ceiling pinned by the test suite.
No public .NET API changes in this release — PublicAPI.Shipped.txt is untouched across
ExcelReader.Core and ExcelReader.Arrow, both target frameworks. The C ABI only gains
exports; every existing one keeps its signature and behavior.
Full Changelog: v3.0.2...v3.1.0
v3.0.2
What's Changed
Added
- ECMA-376 standard encryption support (read-only) — workbooks encrypted with the
"standard" scheme (2.2/3.2/4.2: AES-ECB, SHA-1, 50,000 fixed iterations) now open the
same way agile-encrypted ones already did, viaExcel.Open(..., options)with a
password. Validated against a real third-party fixture (Apache POI's published
VelvetSweatshop-encrypted file), not just a self-forged one. - Rust bindings:
AllRows/read_all_blobfor columnar bulk row reads.
Fixed
- Two container-parsing bugs surfaced by validating standard encryption against a genuine
third-party file: an incorrectverifierHashSizebound, and the CFB reader demanding a
full physical sector on a container's final, unpadded stream. xl_last_error/xl_read_all_blobwere declared in the native C header but missing from
the Windows.defexport files — a latent link error for native/Rust/Python consumers.ExcelDataReader.Read()corrected pending-row handling.
Performance
- Standard-encryption package decryption reuses one cipher transform across all segments
instead of rebuilding it per 4096-byte segment (~3.8x on a large package). ExcelDataReader.GetBytes/GetCharsno longer round-trip through an allocated string.ExcelReader.Arrow's timestamp column reuses the library's existing allocation-free
date/text parser instead of a duplicate hand-rolled one.- Test suite: the encrypted-container mutation test now runs in parallel (deterministic
failure reporting preserved) — full suite ~40s → ~23s.
No public API changes in this release — PublicAPI.Unshipped.txt is empty across
ExcelReader.Core and ExcelReader.Arrow, both target frameworks.
- feat: ECMA-376 standard encryption support, native bulk-read export, and reader/crypto performance fixes by @GabrielMarquezMatte in #105
Full Changelog: v3.0.1...v3.0.2
v3.0.1
What's Changed
- chore: promote public API for v3.0.0 by @github-actions[bot] in #103
- Enhance public API and add trimming compatibility attributes by @GabrielMarquezMatte in #104
Full Changelog: v3.0.0...v3.0.1
v3.0.0
⚠️ Breaking changes
-
IExcelRecordMap<T>.ConfigureExcelRecordMapis now generic in the row writer.
Old:static abstract void ConfigureExcelRecordMap(ExcelRecordMapBuilder<T> builder);
New:static abstract void ConfigureExcelRecordMap<TRow>(ExcelRecordMapBuilder<T, TRow> builder) where TRow : IRowWriter;This lets the mapped record-writer path compile each column's write action against the concrete row writer (
XlsxRowWriter,XlsbRowWriter, ...) instead of dispatching through theIRowWriterinterface on every cell — the same optimization the reflection-based writer already had via its per-TRowplan.Who's affected: only hand-written
IExcelRecordMap<T>implementations. If your types use[ExcelSerializable](the source generator), nothing to do — just recompile. A hand-written implementation needs updating:// before public static void ConfigureExcelRecordMap(ExcelRecordMapBuilder<MyRecord> builder) { ... } // after public static void ConfigureExcelRecordMap<TRow>(ExcelRecordMapBuilder<MyRecord, TRow> builder) where TRow : IRowWriter { ... }
New: encrypted OOXML writing
Excel.EncryptPackage/EncryptPackageAsync: encrypt an OOXML package into an agile-encrypted CFB container (file and stream overloads). Pairs with the encryption reading support shipped in v2.3.0 — round-tripping a password-protected workbook no longer needs a third-party tool.- Underlying pieces now public/available: agile
EncryptionInfodescriptor serialization, the write direction of agile key derivation, and an OLE compound writer generalized to N streams with mini-FAT support.
New: ADO.NET access
ExcelDataReaderimplementsIDataReader, giving Excel/CSV data a standardIDataReadersurface (GetValue,GetSchemaTable,GetOrdinal, typedGetXxxaccessors, etc.) for code that expects one — DataTables, data-binding, existing ADO.NET pipelines.ExcelRowReaderExtensions.Sheets()/ExcelSheet: enumerate a workbook's sheets (index + name) without opening each one.
New: native bindings parity
- Python:
SheetWriter, a streaming write handle —write_rowwith type inference, in-memory streaming, and columnar writing. Encrypted writing wired into the native bindings. - Rust:
Workbook::rows, a zero-allocation lending row cursor, andWorkbook::read_all_decodedfor an RAII row set. - C++: the same
Workbook::rowsbuffer-reusing cursor andread_all_decodedcounterparts. ExcelReader.Arrow:RecordBatchwrite support (previously read-only).
Fixes
- XLSB integers are ~2x smaller. Numeric cells with an integral value in
[-2^29, 2^29)now encode as the 4-byteBrtCellRk(fInt) form instead of always paying for the 8-byteBrtCellReal— matching what Excel itself emits for a sheet of integers. XlsbRowWriter.Write<T>overflow errors now name the type. A caller-definedIUtf8SpanFormattablethat overflows to±Infinityduring numeric conversion previously surfaced a bare "non-finite value" error; it now names the source type, matching the message you already got for a non-numeric value.- Corrupt mini-stream sectors fail loudly.
ReadMiniStreamnow throwsInvalidDataExceptionfor an out-of-bounds mini-sector slice instead of letting the read overflow silently. - Fixed a
NativeAOTstartup crash affecting the Python wheel and C/C++/Rust bindings. The native library no longer pinsIlcInstructionSet=native. That setting baked the build machine's CPU features into the binary as a hard requirement; because the binary is built on one machine and consumed on another (CI runner, or an end user's machine after installing the wheel), a CPU-feature mismatch made the process abort at startup with "The required instruction sets are not supported by the current CPU." — intermittently in CI, and potentially for any user whose CPU lacked whatever the build host happened to have (e.g. AVX-512). Vectorized code paths still light up at runtime on capable CPUs viaVector128/256.IsHardwareAcceleratedchecks, which are unaffected by this change. - Data integrity checks strengthened; mapped-record-writer benchmarks added for the new
ExcelRecordMapBuilder<T, TRow>path. - Dependency bumps:
dorny/paths-filter3→4, analyzer packages.
Compatibility
- Reading is unaffected — no breaking changes to any parser, reader, or the generated
IExcelRowMap<T>side. - .NET 8 and .NET 10 both supported, as before.
v2.3.0
What's Changed
- Streaming writer handle, CLI tool, schema inference, and write/Arrow bindings for C++/Rust/Python by @GabrielMarquezMatte in #93
- Fixing docs by @GabrielMarquezMatte in #94
- chore: promote public API for v2.2.0 by @github-actions[bot] in #95
- Bump the benchmarks group with 1 update by @dependabot[bot] in #97
- Bump the analyzers group with 6 updates by @dependabot[bot] in #96
- Release v2.3.0: encrypted workbooks, parallel CSV, ExcelReader.Arrow package by @GabrielMarquezMatte in #98
Full Changelog: v2.1.3...v2.3.0
v2.2.0
What's Changed
- Streaming writer handle, CLI tool, schema inference, and write/Arrow bindings for C++/Rust/Python by @GabrielMarquezMatte in #93
- Fixing docs by @GabrielMarquezMatte in #94
Full Changelog: v2.1.3...v2.2.0
v2.1.3
What's Changed
- chore: promote public API for v2.1.2 by @github-actions[bot] in #83
- Native bindings performance and fuzz testing improvements by @GabrielMarquezMatte in #84
- Bump Sep from 0.15.2 to 0.17.0 by @dependabot[bot] in #92
- Bump Microsoft.CodeAnalysis.Analyzers and Microsoft.CodeAnalysis.CSharp by @dependabot[bot] in #91
- Bump the test group with 2 updates by @dependabot[bot] in #90
- build(deps): bump softprops/action-gh-release from 2 to 3 by @dependabot[bot] in #88
- build(deps): bump actions/setup-python from 6 to 7 by @dependabot[bot] in #87
- build(deps): bump actions/download-artifact from 6 to 8 by @dependabot[bot] in #86
- Implementing C++ and Rust wrappers packages for native bindings with parsing and reading by @GabrielMarquezMatte in #85
Full Changelog: v2.1.2...v2.1.3
v2.1.2
What's Changed
- Changing python project name by @GabrielMarquezMatte in #80
- Corrigindo tag de linux by @GabrielMarquezMatte in #81
- New native APIs for improved performance by @GabrielMarquezMatte in #82
Full Changelog: v2.1.1...v2.1.2
v2.1.1
What's Changed
- Changing python project name by @GabrielMarquezMatte in #80
Full Changelog: v2.1.0...v2.1.1
v2.1.0
What's Changed
- chore: promote public API for v2.0.1 by @github-actions[bot] in #67
- Promote public API and add fuzz testing for ExcelReader by @GabrielMarquezMatte in #68
- Fix DateTime parsing for ISO dates below year 100 and add tests by @GabrielMarquezMatte in #69
- Bump SharpFuzz from 2.1.1 to 2.3.0 by @dependabot[bot] in #77
- Bump Sep from 0.15.1 to 0.15.2 by @dependabot[bot] in #76
- Bump Microsoft.Testing.Extensions.CodeCoverage from 18.9.0 to 18.10.0 by @dependabot[bot] in #75
- Bump the benchmarks group with 1 update by @dependabot[bot] in #74
- Bump the analyzers group with 6 updates by @dependabot[bot] in #73
- chore(deps): bump actions/checkout from 4 to 7 by @dependabot[bot] in #72
- chore(deps): bump actions/upload-artifact from 4 to 7 by @dependabot[bot] in #71
- chore(deps): bump actions/setup-dotnet from 4 to 6 by @dependabot[bot] in #70
- Update GitHub Actions and analyzer dependencies by @GabrielMarquezMatte in #78
- feat: native C ABI + Python bindings (excelreader package), with bulk read, date parsing, and PyPI publishing by @GabrielMarquezMatte in #79
Full Changelog: v2.0.1...v2.1.0