From d1dcc2ccf7c8727dc02e286db15ca2e2e6cb9b8b Mon Sep 17 00:00:00 2001 From: Gabriel Matte Date: Tue, 27 Oct 2026 17:55:46 -0300 Subject: [PATCH 01/19] fix(zip): verify a sheet entry's CRC-32 when reading stops at the end of its rows The XLSX and XLSB enumerators and the SheetParallel chunk producer stopped at or BrtEndSheetData without reading the rest of the entry, so the checksum, compared only once the declared length had been produced, was never checked when anything followed the sheet data beyond the current buffer. A damaged package then read without error. Reaching the end of the rows now reads the remainder when checksums are verified. --- .../Parser/SheetPipeline/ChunkProducer.cs | 5 ++ .../Reader/PooledStreamRowEnumerator.cs | 17 +++++ .../Reader/Xlsb/XlsbWorkbook.Enumerator.cs | 8 +- .../Reader/Xlsx/XlsxWorkbook.Enumerator.cs | 4 +- .../Reader/Zip/LimitedReadStream.cs | 42 +++++++++++ .../Reader/Zip/PrefetchStream.cs | 2 + .../Reader/Zip/ZipChecksumTests.cs | 75 +++++++++++++++++++ 7 files changed, 147 insertions(+), 6 deletions(-) diff --git a/src/ExcelReader.Core/Parser/SheetPipeline/ChunkProducer.cs b/src/ExcelReader.Core/Parser/SheetPipeline/ChunkProducer.cs index b045a087..4fd34c7a 100644 --- a/src/ExcelReader.Core/Parser/SheetPipeline/ChunkProducer.cs +++ b/src/ExcelReader.Core/Parser/SheetPipeline/ChunkProducer.cs @@ -1,6 +1,7 @@ using System.Buffers; using ExcelReader.Core.Reader; using ExcelReader.Core.Reader.Internal; +using ExcelReader.Core.Reader.Zip; namespace ExcelReader.Core.Parser.SheetPipeline { @@ -33,6 +34,10 @@ internal static async Task RunAsync( int cut = cutter.Cut(buffer.AsSpan(0, filled), out bool ended); if (ended || eof) { + if (source is LimitedReadStream entry) + { + await entry.ReadRemainderForChecksumAsync(ct).ConfigureAwait(false); + } int length = ended ? cut : filled; if (length > 0) { diff --git a/src/ExcelReader.Core/Reader/PooledStreamRowEnumerator.cs b/src/ExcelReader.Core/Reader/PooledStreamRowEnumerator.cs index 278e654e..a5e35186 100644 --- a/src/ExcelReader.Core/Reader/PooledStreamRowEnumerator.cs +++ b/src/ExcelReader.Core/Reader/PooledStreamRowEnumerator.cs @@ -1,6 +1,7 @@ using System.ComponentModel; using System.Diagnostics; using ExcelReader.Core.Reader.Internal; +using ExcelReader.Core.Reader.Zip; namespace ExcelReader.Core.Reader { @@ -117,6 +118,22 @@ private async ValueTask OpenThenFillAsync() await _io.FillAsync(_source, _ct).ConfigureAwait(false); } + // The last row ends before the entry does; reading the rest compares the entry's checksum. + private protected bool Finish() + { + (_source as LimitedReadStream)?.ReadRemainderForChecksum(); + return false; + } + + private protected async ValueTask FinishAsync() + { + if (_source is LimitedReadStream entry) + { + await entry.ReadRemainderForChecksumAsync(_ct).ConfigureAwait(false); + } + return false; + } + private protected void Ensure(int count) { if (_io.Len - _io.Pos < count && !_io.Eof) diff --git a/src/ExcelReader.Core/Reader/Xlsb/XlsbWorkbook.Enumerator.cs b/src/ExcelReader.Core/Reader/Xlsb/XlsbWorkbook.Enumerator.cs index 4884a29b..3e677a2e 100644 --- a/src/ExcelReader.Core/Reader/Xlsb/XlsbWorkbook.Enumerator.cs +++ b/src/ExcelReader.Core/Reader/Xlsb/XlsbWorkbook.Enumerator.cs @@ -100,7 +100,7 @@ void IRowIndexedEnumerator.EnableRowIndex() public bool MoveNext() { _ct.ThrowIfCancellationRequested(); - return MoveNextCore(); + return MoveNextCore() || Finish(); } /// @@ -109,7 +109,7 @@ public ValueTask MoveNextAsync() _ct.ThrowIfCancellationRequested(); if (_ended) { - return new ValueTask(false); + return FinishAsync(); } ResetRow(); if (!_pendingRowHdr) @@ -117,7 +117,7 @@ public ValueTask MoveNextAsync() int seek = SeekRowHdrFromBuffer(); if (seek == 0) { - return new ValueTask(false); + return FinishAsync(); } if (seek == 2) { @@ -137,7 +137,7 @@ private async ValueTask MoveNextRowAsync(bool seekDone) { if (!seekDone && !await SeekRowHdrAsync().ConfigureAwait(false)) { - return false; + return await FinishAsync().ConfigureAwait(false); } _pendingRowHdr = false; _rowIndex = _nextRowIndex; diff --git a/src/ExcelReader.Core/Reader/Xlsx/XlsxWorkbook.Enumerator.cs b/src/ExcelReader.Core/Reader/Xlsx/XlsxWorkbook.Enumerator.cs index cbb17044..18a0c279 100644 --- a/src/ExcelReader.Core/Reader/Xlsx/XlsxWorkbook.Enumerator.cs +++ b/src/ExcelReader.Core/Reader/Xlsx/XlsxWorkbook.Enumerator.cs @@ -137,7 +137,7 @@ public bool MoveNext() { case HeadKind.End: _reachedEnd = true; - return false; + return Finish(); case HeadKind.Row: if (!BeginRow()) { @@ -193,7 +193,7 @@ public ValueTask MoveNextAsync() switch (ClassifyHead()) { case HeadKind.End: - return new ValueTask(false); + return FinishAsync(); case HeadKind.Row: return ReadRowAsync(); default: diff --git a/src/ExcelReader.Core/Reader/Zip/LimitedReadStream.cs b/src/ExcelReader.Core/Reader/Zip/LimitedReadStream.cs index fa843a6b..00a85c3d 100644 --- a/src/ExcelReader.Core/Reader/Zip/LimitedReadStream.cs +++ b/src/ExcelReader.Core/Reader/Zip/LimitedReadStream.cs @@ -1,3 +1,4 @@ +using System.Buffers; using ExcelReader.Core.Reader.Internal; using ExcelReader.Core.Writer.Zip; @@ -95,6 +96,47 @@ public override Task ReadAsync(byte[] buffer, int offset, int count, Cancel return ReadAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask(); } + private bool VerifiesChecksum => _expectedCrc is not null || _inner is PrefetchStream { VerifiesChecksum: true }; + + // A reader stops at the end of the sheet's rows; reading what follows still compares the entry's checksum. + internal void ReadRemainderForChecksum() + { + if (!VerifiesChecksum || _produced >= _declaredLength) + { + return; + } + byte[] scratch = ArrayPool.Shared.Rent(16 * 1024); + try + { + while (Read(scratch.AsSpan()) > 0) + { + } + } + finally + { + ArrayPool.Shared.Return(scratch); + } + } + + internal async ValueTask ReadRemainderForChecksumAsync(CancellationToken ct) + { + if (!VerifiesChecksum || _produced >= _declaredLength) + { + return; + } + byte[] scratch = ArrayPool.Shared.Rent(16 * 1024); + try + { + while (await ReadAsync(scratch.AsMemory(), ct).ConfigureAwait(false) > 0) + { + } + } + finally + { + ArrayPool.Shared.Return(scratch); + } + } + protected override void Dispose(bool disposing) { if (disposing) diff --git a/src/ExcelReader.Core/Reader/Zip/PrefetchStream.cs b/src/ExcelReader.Core/Reader/Zip/PrefetchStream.cs index 5017b3bc..f2ae2cc5 100644 --- a/src/ExcelReader.Core/Reader/Zip/PrefetchStream.cs +++ b/src/ExcelReader.Core/Reader/Zip/PrefetchStream.cs @@ -41,6 +41,8 @@ internal PrefetchStream(Stream inner, long declaredLength = 0, uint? expectedCrc _producer = Task.Run(() => ProduceAsync(_cts.Token), _cts.Token); } + internal bool VerifiesChecksum => _expectedCrc is not null; + public override int Read(byte[] buffer, int offset, int count) { return Read(buffer.AsSpan(offset, count)); diff --git a/tests/ExcelReader.Tests/Reader/Zip/ZipChecksumTests.cs b/tests/ExcelReader.Tests/Reader/Zip/ZipChecksumTests.cs index 0e104524..d6176c40 100644 --- a/tests/ExcelReader.Tests/Reader/Zip/ZipChecksumTests.cs +++ b/tests/ExcelReader.Tests/Reader/Zip/ZipChecksumTests.cs @@ -59,6 +59,35 @@ public void AnIntactPackageStillReads(bool xlsb, bool fromStream, bool prefetch) Assert.Equal((long)Rows * (Rows + 1) / 2, sum); } + [Theory] + [MemberData(nameof(Cases))] + public void ADamagedSheetWithALongTailAfterSheetDataIsRefused(bool xlsb, bool fromStream, bool prefetch) + { + string sheet = xlsb ? "xl/worksheets/sheet1.bin" : "xl/worksheets/sheet1.xml"; + byte[] package = Damage(WithLongTail(Write(xlsb), sheet, xlsb), xlsb, sheet); + var options = new ExcelReaderOptions { PrefetchDecompression = prefetch }; + + InvalidDataException error = Assert.Throws(() => Sum(package, fromStream, options)); + Assert.Contains("CRC-32", error.Message, StringComparison.Ordinal); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task ADamagedSheetWithALongTailIsRefusedByAParallelRead(bool xlsb) + { + string sheet = xlsb ? "xl/worksheets/sheet1.bin" : "xl/worksheets/sheet1.xml"; + byte[] package = Damage(WithLongTail(Write(xlsb), sheet, xlsb), xlsb, sheet); + using IExcelWorkbook workbook = Excel.Open(package); + + await Assert.ThrowsAsync(async () => + await SheetParallel.AggregateAsync( + workbook.FirstSheet, + new RowAggregation { Seed = static () => 0, Accumulate = static (ref int s, Row r) => s++, Combine = static (a, b) => a + b }, + new SheetParallelOptions { DegreeOfParallelism = 4 }, + TestContext.Current.CancellationToken)); + } + [Theory] [InlineData(false)] [InlineData(true)] @@ -118,6 +147,52 @@ private static byte[] Write(bool xlsb, bool sharedStrings = false) return ms.ToArray(); } + // Content after the sheet data that a reader has no reason to parse, long enough to span many buffer fills: + // an XML comment after , or one large record after BrtEndSheetData. + private static byte[] WithLongTail(byte[] package, string entryName, bool xlsb) + { + using var output = new MemoryStream(); + using (var source = new ZipArchive(new MemoryStream(package), ZipArchiveMode.Read)) + using (var target = new ZipArchive(output, ZipArchiveMode.Create, leaveOpen: true)) + { + foreach (ZipArchiveEntry entry in source.Entries) + { + using var copy = new MemoryStream(); + using (Stream data = entry.Open()) + { + data.CopyTo(copy); + } + byte[] content = copy.ToArray(); + if (string.Equals(entry.FullName, entryName, StringComparison.Ordinal)) + { + content = xlsb ? WithTailRecord(content) : WithTailComment(content); + } + using Stream written = target.CreateEntry(entry.FullName, CompressionLevel.NoCompression).Open(); + written.Write(content); + } + } + return output.ToArray(); + } + + private static byte[] WithTailComment(byte[] xml) + { + string text = Encoding.UTF8.GetString(xml); + return Encoding.UTF8.GetBytes(text.Replace("", "", StringComparison.Ordinal)); + } + + // BrtEndSheetData is record 146 with no payload: 0x92 0x01 0x00. The tail record is id 0x7F, length 1 MiB. + private static byte[] WithTailRecord(byte[] bin) + { + int end = bin.AsSpan().LastIndexOf(new byte[] { 0x92, 0x01, 0x00 }) + 3; + Assert.True(end > 3, "BrtEndSheetData not found"); + byte[] tail = new byte[4 + (1 << 20)]; + tail[0] = 0x7F; + tail[1] = 0x80; + tail[2] = 0x80; + tail[3] = 0x40; + return [.. bin.AsSpan(0, end), .. tail, .. bin.AsSpan(end)]; + } + // The package is stored, not deflated, so one changed letter of the cell text "text" stays valid // XML or BIFF12 and only the checksum can tell. private static byte[] Damage(byte[] package, bool xlsb, string entryName) From a9c21924f7dc7d4f46b6bd534385db07510ba03c Mon Sep 17 00:00:00 2001 From: Gabriel Matte Date: Tue, 27 Oct 2026 18:01:19 -0300 Subject: [PATCH 02/19] perf(writer): resolve date style variants without taking a lock StyleTable.DateVariant took a lock on every date cell written under a style, and parallel record writers share one table across workers. A styled date column made an 8-way parallel XLSX write 30% slower than the same write unstyled. Known variants are now read from a copy-on-write array; only the first resolution of a style takes the lock. --- .../Writer/Internal/StyleTable.cs | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/ExcelReader.Core/Writer/Internal/StyleTable.cs b/src/ExcelReader.Core/Writer/Internal/StyleTable.cs index 940a73c1..5aaf4cbe 100644 --- a/src/ExcelReader.Core/Writer/Internal/StyleTable.cs +++ b/src/ExcelReader.Core/Writer/Internal/StyleTable.cs @@ -15,7 +15,8 @@ internal sealed class StyleTable private readonly Dictionary _indices = []; private readonly List _styles = []; private readonly HashSet _customFormats = new(StringComparer.Ordinal); - private readonly Dictionary _dateVariants = []; + private readonly Lock _dateVariantGate = new(); + private int[] _dateVariants = []; internal StyleTable() { @@ -51,18 +52,33 @@ internal int Add(CellStyle style) return index; } - // Locked because parallel record writers call this from worker threads. + // Parallel record writers resolve this per date cell on every worker, so a known variant is read + // without the lock; entries hold variant + 1, leaving 0 for "not resolved yet". internal int DateVariant(int styleId) { - lock (_dateVariants) + int[] known = Volatile.Read(ref _dateVariants); + if ((uint)styleId < (uint)known.Length && known[styleId] != 0) { - if (_dateVariants.TryGetValue(styleId, out int variant)) + return known[styleId] - 1; + } + return AddDateVariant(styleId); + } + + private int AddDateVariant(int styleId) + { + lock (_dateVariantGate) + { + int[] known = _dateVariants; + if ((uint)styleId < (uint)known.Length && known[styleId] != 0) { - return variant; + return known[styleId] - 1; } CellStyle style = _styles[styleId]; - variant = style.NumberFormat is null ? Add(style with { NumberFormat = DateStyle.NumberFormat }) : styleId; - _dateVariants[styleId] = variant; + int variant = style.NumberFormat is null ? Add(style with { NumberFormat = DateStyle.NumberFormat }) : styleId; + int[] next = new int[Math.Max(known.Length, styleId + 1)]; + known.CopyTo(next, 0); + next[styleId] = variant + 1; + Volatile.Write(ref _dateVariants, next); return variant; } } From 700a4dcba9a67bd9c004162d2fd68c779564d730 Mon Sep 17 00:00:00 2001 From: Gabriel Matte Date: Tue, 27 Oct 2026 18:05:54 -0300 Subject: [PATCH 03/19] perf(parser): resolve integral enum cells through a long lookup --- .../Parser/Internal/ColumnParserFactory.cs | 32 +++++++ .../Parser/EnumParsingTests.cs | 89 +++++++++++++++++++ 2 files changed, 121 insertions(+) diff --git a/src/ExcelReader.Core/Parser/Internal/ColumnParserFactory.cs b/src/ExcelReader.Core/Parser/Internal/ColumnParserFactory.cs index e9867871..b1186ca5 100644 --- a/src/ExcelReader.Core/Parser/Internal/ColumnParserFactory.cs +++ b/src/ExcelReader.Core/Parser/Internal/ColumnParserFactory.cs @@ -480,6 +480,7 @@ private static class EnumCache private static readonly FrozenDictionary _nameMap = BuildNameMap(); private static readonly FrozenDictionary.AlternateLookup> _alternateLookup = _nameMap.GetAlternateLookup>(); private static readonly FrozenDictionary _valueMap = BuildValueMap(); + private static readonly FrozenDictionary _longMap = _valueMap.Where(p => p.Key >= long.MinValue && p.Key <= long.MaxValue).ToFrozenDictionary(p => (long)p.Key, p => p.Value); private static FrozenDictionary BuildNameMap() { @@ -513,6 +514,29 @@ private static Int128 Numeric(TEnum value) return Convert.ToInt64(value, CultureInfo.InvariantCulture); } + private static bool TryParseLong(ReadOnlySpan text, out long result) + { + result = 0; + bool negative = !text.IsEmpty && text[0] == (byte)'-'; + ReadOnlySpan digits = negative ? text[1..] : text; + if (digits.IsEmpty || digits.Length > 18) + { + return false; + } + long acc = 0; + foreach (byte b in digits) + { + uint digit = (uint)(b - (byte)'0'); + if (digit > 9) + { + return false; + } + acc = acc * 10 + digit; + } + result = negative ? -acc : acc; + return true; + } + // Integer text is parsed exactly; a double cannot tell apart integers above 2^53. private static bool TryGetIntegral(in Cell cell, double number, out Int128 integral) { @@ -534,6 +558,14 @@ public static bool TryParse(in Cell cell, out TEnum value) { if (cell.Type is CellType.Number or CellType.Date && cell.TryGetDouble(out double d)) { + if (TryParseLong(cell.Value, out long small)) + { + return _longMap.TryGetValue(small, out value); + } + if (cell.Value.IsEmpty && d == Math.Truncate(d) && d is >= -9223372036854775808.0 and < 9223372036854775808.0) + { + return _longMap.TryGetValue((long)d, out value); + } if (!TryGetIntegral(in cell, d, out Int128 integral)) { value = default; diff --git a/tests/ExcelReader.Tests/Parser/EnumParsingTests.cs b/tests/ExcelReader.Tests/Parser/EnumParsingTests.cs index f46a6157..dc2a24ec 100644 --- a/tests/ExcelReader.Tests/Parser/EnumParsingTests.cs +++ b/tests/ExcelReader.Tests/Parser/EnumParsingTests.cs @@ -76,6 +76,95 @@ public void Should_ParseAnUnsignedEnum_When_AMemberExceedsInt64(string text, ulo } } + private enum Signed : long + { + Min = long.MinValue, + Negative = -5, + Zero = 0, + Max = long.MaxValue, + } + + private enum Wide : ulong + { + AboveLong = 9223372036854775808, + Max = ulong.MaxValue, + } + + [Theory] + [InlineData("-9223372036854775808", long.MinValue)] + [InlineData("-5", -5L)] + [InlineData("-0", 0L)] + [InlineData("0", 0L)] + [InlineData("9223372036854775807", long.MaxValue)] + public void Should_ResolveSignedMembers_When_TheyReachTheInt64Boundaries(string text, long expected) + { + Assert.True(TryParse(CellType.Number, text, out Signed value)); + Assert.Equal((Signed)expected, value); + } + + [Theory] + [InlineData("9223372036854775808")] + [InlineData("-9223372036854775809")] + [InlineData("-4")] + [InlineData("-")] + [InlineData("5.5")] + [InlineData("1E3")] + public void Should_RejectUndeclaredSignedValues(string text) + { + Assert.False(TryParse(CellType.Number, text, out Signed _)); + } + + [Theory] + [InlineData("9223372036854775808", 9223372036854775808UL)] + [InlineData("18446744073709551615", ulong.MaxValue)] + public void Should_ResolveMembersOnlyRepresentableAsUnsigned(string text, ulong expected) + { + Assert.True(TryParse(CellType.Number, text, out Wide value)); + Assert.Equal((Wide)expected, value); + Assert.False(TryParse(CellType.Number, "9223372036854775807", out Wide _)); + } + + [Theory] + [InlineData(-5.0, -5L)] + [InlineData(0.0, 0L)] + [InlineData(-9223372036854775808.0, long.MinValue)] + public void Should_ResolveBinaryNumbers_When_TheyAreIntegral(double number, long expected) + { + Cell cell = new(CellType.Number, default, number, hasNumber: true, styleIndex: 0); + + Assert.True(ExcelCellReaders.Enum(in cell, default, out Signed value)); + Assert.Equal((Signed)expected, value); + } + + [Theory] + [InlineData(-4.0)] + [InlineData(0.5)] + [InlineData(9223372036854775808.0)] + [InlineData(double.NaN)] + [InlineData(double.PositiveInfinity)] + public void Should_RejectBinaryNumbers_When_NotADeclaredIntegral(double number) + { + Cell cell = new(CellType.Number, default, number, hasNumber: true, styleIndex: 0); + + Assert.False(ExcelCellReaders.Enum(in cell, default, out Signed _)); + } + + [Fact] + public void Should_ResolveAUnsignedMemberFromABinaryNumber() + { + Cell cell = new(CellType.Number, default, 9223372036854775808.0, hasNumber: true, styleIndex: 0); + + Assert.True(ExcelCellReaders.Enum(in cell, default, out Wide value)); + Assert.Equal(Wide.AboveLong, value); + } + + [Fact] + public void Should_ResolveAnAliasFromNumericText() + { + Assert.True(TryParse(CellType.Number, "1", out Aliased value)); + Assert.Equal(Aliased.First, value); + } + [Fact] public void Should_ReadABinaryNumberAsItsStoredDouble() { From b829cc1c67cd5d7d3ba74db4131514d14722b5fc Mon Sep 17 00:00:00 2001 From: Gabriel Matte Date: Tue, 27 Oct 2026 18:05:54 -0300 Subject: [PATCH 04/19] perf(reader): reuse boxed booleans in SheetDataReader.GetValue --- src/ExcelReader.Core/Reader/SheetDataReader.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ExcelReader.Core/Reader/SheetDataReader.cs b/src/ExcelReader.Core/Reader/SheetDataReader.cs index 0b9a00ab..7693956c 100644 --- a/src/ExcelReader.Core/Reader/SheetDataReader.cs +++ b/src/ExcelReader.Core/Reader/SheetDataReader.cs @@ -219,6 +219,14 @@ private static Type TypeOf(Cell cell) }; } + private static readonly object BoxedTrue = true; + private static readonly object BoxedFalse = false; + + private static object Boxed(bool value) + { + return value ? BoxedTrue : BoxedFalse; + } + /// public object GetValue(int i) { @@ -228,7 +236,7 @@ public object GetValue(int i) CellType.Empty => DBNull.Value, CellType.Number => cell.TryGetDouble(out double d) ? d : cell.GetString(), CellType.Date => cell.TryGetDateTime(_isDate1904, out DateTime dt) ? dt : cell.GetString(), - CellType.Boolean => ExcelCellReaders.Bool(in cell, default, out bool b) ? b : cell.GetString(), + CellType.Boolean => ExcelCellReaders.Bool(in cell, default, out bool b) ? Boxed(b) : cell.GetString(), _ => cell.GetString(), }; } From df8cb0cde80d177effe3ecee643a96c1cb64b9b3 Mon Sep 17 00:00:00 2001 From: Gabriel Matte Date: Tue, 27 Oct 2026 18:02:28 -0300 Subject: [PATCH 05/19] perf(native): stop allocating a closure per written cell --- src/ExcelReader.Native/Exports.Writer.cs | 33 +++++++++++++++++++----- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/ExcelReader.Native/Exports.Writer.cs b/src/ExcelReader.Native/Exports.Writer.cs index ea8186c4..aec0ac74 100644 --- a/src/ExcelReader.Native/Exports.Writer.cs +++ b/src/ExcelReader.Native/Exports.Writer.cs @@ -212,43 +212,43 @@ public static int WriteString(nint handle, byte* value, int valueLength) [UnmanagedCallersOnly(EntryPoint = "xl_write_int64")] public static int WriteInt64(nint handle, long value) { - return RunWriterOp(handle, writerHandle => writerHandle.WriteInt64(value)); + return RunWriterOp(handle, value, static (writerHandle, state) => writerHandle.WriteInt64(state)); } [UnmanagedCallersOnly(EntryPoint = "xl_write_float64")] public static int WriteFloat64(nint handle, double value) { - return RunWriterOp(handle, writerHandle => writerHandle.WriteFloat64(value)); + return RunWriterOp(handle, value, static (writerHandle, state) => writerHandle.WriteFloat64(state)); } [UnmanagedCallersOnly(EntryPoint = "xl_write_bool")] public static int WriteBool(nint handle, int value) { - return RunWriterOp(handle, writerHandle => writerHandle.WriteBool(value != 0)); + return RunWriterOp(handle, value != 0, static (writerHandle, state) => writerHandle.WriteBool(state)); } [UnmanagedCallersOnly(EntryPoint = "xl_write_date")] public static int WriteDate(nint handle, int daysSinceEpoch) { - return RunWriterOp(handle, writerHandle => writerHandle.WriteDate(daysSinceEpoch)); + return RunWriterOp(handle, daysSinceEpoch, static (writerHandle, state) => writerHandle.WriteDate(state)); } [UnmanagedCallersOnly(EntryPoint = "xl_write_time")] public static int WriteTime(nint handle, long microsecondsSinceMidnight) { - return RunWriterOp(handle, writerHandle => writerHandle.WriteTime(microsecondsSinceMidnight)); + return RunWriterOp(handle, microsecondsSinceMidnight, static (writerHandle, state) => writerHandle.WriteTime(state)); } [UnmanagedCallersOnly(EntryPoint = "xl_write_timestamp")] public static int WriteTimestamp(nint handle, long microsecondsSinceEpoch) { - return RunWriterOp(handle, writerHandle => writerHandle.WriteTimestamp(microsecondsSinceEpoch)); + return RunWriterOp(handle, microsecondsSinceEpoch, static (writerHandle, state) => writerHandle.WriteTimestamp(state)); } [UnmanagedCallersOnly(EntryPoint = "xl_write_null")] public static int WriteNull(nint handle, int type) { - return RunWriterOp(handle, writerHandle => writerHandle.WriteNull(type)); + return RunWriterOp(handle, type, static (writerHandle, state) => writerHandle.WriteNull(state)); } [UnmanagedCallersOnly(EntryPoint = "xl_end_row")] @@ -355,6 +355,25 @@ private static int RunWriterOp(nint handle, Action operation } } + private static int RunWriterOp(nint handle, TState state, Action operation) + { + NativeApi.ClearLastError(); + if (!TryResolveWriter(handle, out NativeWriterHandle? writerHandle)) + { + return NativeStatus.InvalidHandle; + } + try + { + operation(writerHandle, state); + return NativeStatus.Ok; + } + catch (Exception exception) + { + NativeApi.SetLastError(exception.Message); + return NativeStatus.Error; + } + } + private static bool TryResolveWriter(nint handle, [NotNullWhen(true)] out NativeWriterHandle? writerHandle) { writerHandle = NativeHandleTable.Resolve(handle); From 1f0e4a5472e096d5f76c8db51c42cc542befdd83 Mon Sep 17 00:00:00 2001 From: Gabriel Matte Date: Tue, 27 Oct 2026 18:03:23 -0300 Subject: [PATCH 06/19] perf(python): decode row blobs from a memoryview with a prebuilt cell-type tuple --- python/src/excelreader/reader.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/python/src/excelreader/reader.py b/python/src/excelreader/reader.py index 8b50b178..b6960794 100644 --- a/python/src/excelreader/reader.py +++ b/python/src/excelreader/reader.py @@ -42,6 +42,7 @@ _FORMATS = _native.FORMATS _CELL_HEADER = struct.Struct(" Iterator[list[Cell]]: written = ctypes.c_int32() capacity = _INITIAL_ROW_BUFFER buffer = ctypes.create_string_buffer(capacity) + view = memoryview(buffer) while True: status = self._lib.xl_rows_next(cursor, buffer, capacity, ctypes.byref(written)) if status == _native.XL_EOF: @@ -253,9 +255,10 @@ def rows(self) -> Iterator[list[Cell]]: if status == _native.XL_BUFFER_TOO_SMALL: capacity = written.value buffer = ctypes.create_string_buffer(capacity) + view = memoryview(buffer) continue _check(status) - yield _decode_row(buffer[: written.value], written.value, date1904) + yield _decode_row(view, written.value, date1904) finally: self._close_rows(cursor) @@ -522,16 +525,16 @@ def _info(self) -> _native.NativeTableInfo: return info -def _decode_row(blob: bytes, length: int, date1904: bool) -> list[Cell]: +def _decode_row(blob: memoryview, length: int, date1904: bool) -> list[Cell]: count = struct.unpack_from(" Date: Tue, 27 Oct 2026 18:03:42 -0300 Subject: [PATCH 07/19] perf(python): pass written strings as bytes and dispatch cells on exact type --- python/src/excelreader/_native.py | 2 +- python/src/excelreader/writer_handle.py | 28 +++++++++++++++++-------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/python/src/excelreader/_native.py b/python/src/excelreader/_native.py index f30c5f64..3e2614bd 100644 --- a/python/src/excelreader/_native.py +++ b/python/src/excelreader/_native.py @@ -614,7 +614,7 @@ def _bind(lib: ctypes.CDLL) -> ctypes.CDLL: lib.xl_start_row.argtypes = [ctypes.c_void_p] lib.xl_start_row.restype = ctypes.c_int32 - lib.xl_write_string.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_uint8), ctypes.c_int32] + lib.xl_write_string.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int32] lib.xl_write_string.restype = ctypes.c_int32 lib.xl_write_int64.argtypes = [ctypes.c_void_p, ctypes.c_int64] diff --git a/python/src/excelreader/writer_handle.py b/python/src/excelreader/writer_handle.py index a557ca43..d523fb1c 100644 --- a/python/src/excelreader/writer_handle.py +++ b/python/src/excelreader/writer_handle.py @@ -122,16 +122,20 @@ def write_row(self, values: Sequence[Any]) -> None: def _write_cell(self, handle: ctypes.c_void_p, value: Any) -> int: lib = self._lib + kind = type(value) + if kind is str: + raw = value.encode("utf-8") + return lib.xl_write_string(handle, raw, _native.int32_len(raw)) + if kind is int: + return lib.xl_write_int64(handle, value) + if kind is float: + return lib.xl_write_float64(handle, value) + if kind is bool: + return lib.xl_write_bool(handle, 1 if value else 0) if value is None: return lib.xl_write_string(handle, None, 0) - if isinstance(value, tuple): + if kind is tuple: return lib.xl_write_null(handle, int(value[1])) - if isinstance(value, bool): - return lib.xl_write_bool(handle, 1 if value else 0) - if isinstance(value, int): - return lib.xl_write_int64(handle, value) - if isinstance(value, float): - return lib.xl_write_float64(handle, value) if isinstance(value, datetime.datetime): if value.tzinfo is not None: value = value.astimezone(datetime.timezone.utc).replace(tzinfo=None) @@ -143,8 +147,14 @@ def _write_cell(self, handle: ctypes.c_void_p, value: Any) -> int: return lib.xl_write_time( handle, (value.hour * 3600 + value.minute * 60 + value.second) * 1_000_000 + value.microsecond ) - pointer, length = _encode(value) - return lib.xl_write_string(handle, pointer, length) + if isinstance(value, bool): + return lib.xl_write_bool(handle, 1 if value else 0) + if isinstance(value, int): + return lib.xl_write_int64(handle, value) + if isinstance(value, float): + return lib.xl_write_float64(handle, value) + raw = value.encode("utf-8") + return lib.xl_write_string(handle, raw, _native.int32_len(raw)) def _finished_bytes(self, handle: ctypes.c_void_p) -> bytes: buffer = _native.NativeBuffer() From 09b1cb94443b57697cef20e97b41c6b707bf5360 Mon Sep 17 00:00:00 2001 From: Gabriel Matte Date: Tue, 27 Oct 2026 18:10:10 -0300 Subject: [PATCH 08/19] perf(xlsx): keep formula cells on the canonical cell path --- .../Reader/Xlsx/XlsxWorkbook.Enumerator.cs | 59 ++++++- .../Reader/Xlsx/XlsxCanonicalCellTests.cs | 147 ++++++++++++++++-- 2 files changed, 194 insertions(+), 12 deletions(-) diff --git a/src/ExcelReader.Core/Reader/Xlsx/XlsxWorkbook.Enumerator.cs b/src/ExcelReader.Core/Reader/Xlsx/XlsxWorkbook.Enumerator.cs index 18a0c279..8a76606d 100644 --- a/src/ExcelReader.Core/Reader/Xlsx/XlsxWorkbook.Enumerator.cs +++ b/src/ExcelReader.Core/Reader/Xlsx/XlsxWorkbook.Enumerator.cs @@ -537,10 +537,19 @@ private int TryParseCanonicalCell(ReadOnlySpan buf, int p, ref int nextCol nextCol = col + 1; return i + 2; } - if (kind == Kind.Inline || !buf.Slice(i, 4).SequenceEqual(">"u8)) + if (kind == Kind.Inline) { return -1; } + if (!buf.Slice(i, 4).SequenceEqual(">"u8)) + { + int end = TryParseCanonicalCellBody(buf, i, col, style, kind); + if (end >= 0) + { + nextCol = col + 1; + } + return end; + } int start = i + 4; int v = ScanCanonicalValue(buf, start, kind, out int sharedIndex); if (v < 0 || buf.Length - v < 8 || !buf.Slice(v, 8).SequenceEqual(""u8)) @@ -552,6 +561,54 @@ private int TryParseCanonicalCell(ReadOnlySpan buf, int p, ref int nextCol return v + 8; } + [MethodImpl(MethodImplOptions.NoInlining)] + private int TryParseCanonicalCellBody(ReadOnlySpan buf, int i, int col, int style, Kind kind) + { + if (buf[i] != (byte)'>') + { + return -1; + } + int start = SkipFormula(buf, i + 1); + if (start < 0 || !buf[start..].StartsWith(""u8)) + { + return -1; + } + start += 3; + int v = ScanCanonicalValue(buf, start, kind, out int sharedIndex); + if (v < 0 || !buf[v..].StartsWith(""u8)) + { + return -1; + } + EmitCanonicalCell(kind, buf, start, v, col, style, sharedIndex); + return v + 8; + } + + // Formula text and attributes hold no raw '<', so the next '<' after the start tag is the end tag. + private static int SkipFormula(ReadOnlySpan buf, int p) + { + if (buf.Length - p < 3 || buf[p] != (byte)'<' || buf[p + 1] != (byte)'f' || !IsBoundary(buf[p + 2])) + { + return -1; + } + int gt = buf[(p + 2)..].IndexOfAny((byte)'<', (byte)'>'); + if (gt < 0 || buf[p + 2 + gt] != (byte)'>') + { + return -1; + } + gt += p + 2; + if (buf[gt - 1] == (byte)'/') + { + return gt + 1; + } + int lt = buf[(gt + 1)..].IndexOf((byte)'<'); + if (lt < 0) + { + return -1; + } + lt += gt + 1; + return buf[lt..].StartsWith(""u8) ? lt + 4 : -1; + } + // A shared string's value must be its index in at most 9 digits; any other value runs to the next markup. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int ScanCanonicalValue(ReadOnlySpan buf, int start, Kind kind, out int sharedIndex) diff --git a/tests/ExcelReader.Tests/Reader/Xlsx/XlsxCanonicalCellTests.cs b/tests/ExcelReader.Tests/Reader/Xlsx/XlsxCanonicalCellTests.cs index 0323414f..ecd949ea 100644 --- a/tests/ExcelReader.Tests/Reader/Xlsx/XlsxCanonicalCellTests.cs +++ b/tests/ExcelReader.Tests/Reader/Xlsx/XlsxCanonicalCellTests.cs @@ -24,6 +24,125 @@ public void CellsInExcelsShapeReadTheSameAsThroughTheGeneralPath() Assert.Equal(expected, actual); } + private static readonly string[] FormulaCells = + [ + """A{r}+13""", + """A1*24.5""", + """6""", + """{1;2}45000""", + """IF(A1>2,"a<b",'q"')a<b""", + """A1&"x"A_x0041_""", + """"x" x """, + """TRUE()1""", + """1/0#DIV/0!""", + """"s"2""", + """NOW()""", + """A1""", + """A1""", + """A1>20""", + """7""", + """RAND()0.25""", + """8""", + """X2024-01-02T03:04:05""", + """A19""", + """"y"no ref""", + """"s"12345678901""", + """""", + ]; + + [Fact] + public void FormulaCellsReadTheSameOnTheCanonicalPathAsOnTheGeneralPath() + { + AssertPathsAgree(FormulaCells, prefixedAgrees: true); + } + + [Fact] + public void FormulaCellsReadTheirCachedValues() + { + using XlsxWorkbook reader = Excel.FromXlsx(new MemoryStream(Workbook(Rows(FormulaCells, 1)))); + using XlsxWorkbook.Enumerator rows = reader.FirstSheet.GetEnumerator(); + Assert.True(rows.MoveNext()); + Row row = rows.Current; + + Assert.True(row[0].TryGetDouble(out double a)); + Assert.Equal(3, a); + Assert.Equal("6", row[2].GetString()); + Assert.Equal(CellType.Date, row[3].Type); + Assert.Equal("a{StylesInner("")}"); + + List expected = Snapshot(general); + + Assert.Equal(RowCount, expected.Count); + Assert.Equal(expected, Snapshot(new MemoryStream(plain))); + Assert.Equal(expected, TrickleSnapshot(plain)); + if (!prefixedAgrees) + { + return; + } + string prefixedSheet = sheet.Replace("<", "{StylesInner("")}"); + return ms.ToArray(); + } + + private static string Rows(string[] cells, int rows) + { + var sb = new StringBuilder(); + for (int r = 1; r <= rows; r++) + { + string n = r.ToString(CultureInfo.InvariantCulture); + sb.Append(CultureInfo.InvariantCulture, $""""""); + foreach (string cell in cells) + { + sb.Append(cell.Replace("{r}", n, StringComparison.Ordinal)); + } + sb.Append(""); + } + return sb.ToString(); + } + + // Seven bytes per read, so every row is cut and re-parsed at every few bytes of its cells. + private static List TrickleSnapshot(byte[] workbook) + { + using XlsxWorkbook reader = Excel.FromXlsx(new MemoryStream(workbook)); + reader.OpenSheetWithoutPrefetch(0).Dispose(); + using var sheet = new MemoryStream(); + using (Stream source = reader.OpenSheetStream(0)) + { + source.CopyTo(sheet); + } + reader.Lifetime.Acquire(reader); + using var rows = new XlsxWorkbook.Enumerator(reader, new TrickleStream(sheet.ToArray())); + var snapshot = new List(); + while (rows.MoveNext()) + { + snapshot.Add(Render(rows.Current)); + } + return snapshot; + } + private static string SharedStrings(string p) { return $"<{p}si><{p}t>alpha<{p}si><{p}t>beta<{p}si><{p}t>gamma"; @@ -66,20 +185,26 @@ private static List Snapshot(Stream workbook) var rows = new List(); foreach (Row row in reader.FirstSheet) { - var sb = new StringBuilder(); - foreach (RowCell rowCell in row.Cells) + rows.Add(Render(row)); + } + return rows; + } + + private static string Render(Row row) + { + var sb = new StringBuilder(); + foreach (RowCell rowCell in row.Cells) + { + Cell cell = rowCell.Value; + string number = "-"; + if (cell.TryGetDouble(out double value)) { - Cell cell = rowCell.Value; - string number = "-"; - if (cell.TryGetDouble(out double value)) - { - number = value.ToString("R", CultureInfo.InvariantCulture); - } - sb.Append(CultureInfo.InvariantCulture, $"{rowCell.ColumnIndex}:{cell.Type}:{cell.StyleIndex}:{cell.GetString()}:{number}|"); + number = value.ToString("R", CultureInfo.InvariantCulture); } - rows.Add(sb.ToString()); + string date = cell.TryGetDateTime(false, out DateTime dt) ? dt.ToString("O", CultureInfo.InvariantCulture) : "-"; + sb.Append(CultureInfo.InvariantCulture, $"{rowCell.ColumnIndex}:{cell.Type}:{cell.StyleIndex}:{cell.GetString()}:{number}:{date}|"); } - return rows; + return sb.ToString(); } } } From 2f73e72b7620175e5cf2b6e0639960b714a25dc7 Mon Sep 17 00:00:00 2001 From: Gabriel Matte Date: Tue, 27 Oct 2026 18:14:12 -0300 Subject: [PATCH 09/19] perf(xlsx): hand inline-string cells from the canonical path straight to the inline emitter --- .../Reader/Xlsx/XlsxWorkbook.Enumerator.cs | 18 +++---- .../Reader/Xlsx/XlsxCanonicalCellTests.cs | 49 +++++++++++++++++++ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/ExcelReader.Core/Reader/Xlsx/XlsxWorkbook.Enumerator.cs b/src/ExcelReader.Core/Reader/Xlsx/XlsxWorkbook.Enumerator.cs index 8a76606d..125a0866 100644 --- a/src/ExcelReader.Core/Reader/Xlsx/XlsxWorkbook.Enumerator.cs +++ b/src/ExcelReader.Core/Reader/Xlsx/XlsxWorkbook.Enumerator.cs @@ -477,7 +477,7 @@ private int ParseCellSpan(byte[] buf, int len, int p) } else if (kind == Kind.Inline) { - int end = TryEmitPlainInline(buf, len, p, col, style); + int end = TryEmitPlainInline(buf.AsSpan(0, len), p, col, style); if (end >= 0) { return end; @@ -537,10 +537,6 @@ private int TryParseCanonicalCell(ReadOnlySpan buf, int p, ref int nextCol nextCol = col + 1; return i + 2; } - if (kind == Kind.Inline) - { - return -1; - } if (!buf.Slice(i, 4).SequenceEqual(">"u8)) { int end = TryParseCanonicalCellBody(buf, i, col, style, kind); @@ -568,6 +564,10 @@ private int TryParseCanonicalCellBody(ReadOnlySpan buf, int i, int col, in { return -1; } + if (kind == Kind.Inline) + { + return TryEmitPlainInline(buf, i + 1, col, style); + } int start = SkipFormula(buf, i + 1); if (start < 0 || !buf[start..].StartsWith(""u8)) { @@ -748,20 +748,20 @@ private int TryEmitSharedIndex(byte[] buf, int len, int valueStart, int col, int return i + 8; } - private int TryEmitPlainInline(byte[] buf, int len, int p, int col, int style) + private int TryEmitPlainInline(ReadOnlySpan buf, int p, int col, int style) { - if (!buf.AsSpan(p, Math.Min(7, len - p)).StartsWith(""u8)) + if (!buf[p..].StartsWith(""u8)) { return -1; } int textStart = p + 7; - int rel = XlsxXml.IndexOfMarkup(buf.AsSpan(textStart, len - textStart), out bool mayEscape); + int rel = XlsxXml.IndexOfMarkup(buf[textStart..], out bool mayEscape); if (rel < 0) { return -1; } int lt = textStart + rel; - if (!buf.AsSpan(lt, Math.Min(13, len - lt)).StartsWith(""u8) || (mayEscape && buf.AsSpan(textStart, rel).IndexOf("_x"u8) >= 0)) + if (!buf[lt..].StartsWith(""u8) || (mayEscape && buf.Slice(textStart, rel).IndexOf("_x"u8) >= 0)) { return -1; } diff --git a/tests/ExcelReader.Tests/Reader/Xlsx/XlsxCanonicalCellTests.cs b/tests/ExcelReader.Tests/Reader/Xlsx/XlsxCanonicalCellTests.cs index ecd949ea..73a0f817 100644 --- a/tests/ExcelReader.Tests/Reader/Xlsx/XlsxCanonicalCellTests.cs +++ b/tests/ExcelReader.Tests/Reader/Xlsx/XlsxCanonicalCellTests.cs @@ -80,6 +80,55 @@ public void FormulaCellsReadTheirCachedValues() Assert.Equal("no ref", row[19].GetString()); } + private static readonly string[] InlineCells = + [ + """plain {r}""", + """rich text""", + """ spaced """, + """A_x0042_C""", + """under_score""", + """""", + """""", + """a&b""", + """xph""", + """styled""", + """no ref""", + """""", + """""", + """a_x000D_b""", + ]; + + [Fact] + public void InlineCellsReadTheSameOnTheCanonicalPathAsOnTheGeneralPath() + { + AssertPathsAgree(InlineCells, prefixedAgrees: true); + } + + [Fact] + public void AnInlineCellWithAValueReadsTheSameOnTheCanonicalPath() + { + AssertPathsAgree(["""5""", """xy"""], prefixedAgrees: false); + } + + [Fact] + public void InlineCellsReadTheirText() + { + using XlsxWorkbook reader = Excel.FromXlsx(new MemoryStream(Workbook(Rows(InlineCells, 1)))); + using XlsxWorkbook.Enumerator rows = reader.FirstSheet.GetEnumerator(); + Assert.True(rows.MoveNext()); + Row row = rows.Current; + + Assert.Equal("plain 1", row[0].GetString()); + Assert.Equal("rich text", row[1].GetString()); + Assert.Equal(" spaced ", row[2].GetString()); + Assert.Equal("ABC", row[3].GetString()); + Assert.Equal("under_score", row[4].GetString()); + Assert.Equal("a&b", row[7].GetString()); + Assert.Equal("x", row[8].GetString()); + Assert.Equal(1, row[9].StyleIndex); + Assert.Equal("no ref", row[10].GetString()); + } + private static void AssertPathsAgree(string[] cells, bool prefixedAgrees) { const int RowCount = 300; From b51be5fdde2ae2ee57cdf0abc9e92e18864fba7c Mon Sep 17 00:00:00 2001 From: Gabriel Matte Date: Tue, 27 Oct 2026 20:54:29 -0300 Subject: [PATCH 10/19] fix(trim): clear IL2087 and IL2073 from the bug-hunt fixes SyncRowEnumerator boxed value-type models through RuntimeHelpers.GetUninitializedObject(typeof(T)), which needs constructor annotations on T; RuntimeHelpers.Box carries no trimming requirement and also boxes Nullable correctly. SheetDataReader.TypeOf now carries the same DynamicallyAccessedMembers annotation as the GetFieldType it feeds. Both broke builds that enable the trim and AOT analyzers on Core, such as the NativeAOT publishes. --- src/ExcelReader.Core/Parser/SyncRowEnumerator.cs | 9 +-------- src/ExcelReader.Core/Reader/SheetDataReader.cs | 1 + 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/ExcelReader.Core/Parser/SyncRowEnumerator.cs b/src/ExcelReader.Core/Parser/SyncRowEnumerator.cs index 517a3107..be7b05be 100644 --- a/src/ExcelReader.Core/Parser/SyncRowEnumerator.cs +++ b/src/ExcelReader.Core/Parser/SyncRowEnumerator.cs @@ -45,11 +45,6 @@ private protected SyncRowEnumerator(TRows rows) object? IEnumerator.Current => typeof(T).IsByRefLike ? throw new NotSupportedException() : Box(Project()); - private sealed class RawData - { - public byte Data; - } - // T allows ref struct, so the language refuses (object)value; the byref-like case is excluded by the caller. private static object? Box(T value) { @@ -57,9 +52,7 @@ private sealed class RawData { return Unsafe.As(ref value); } - object box = RuntimeHelpers.GetUninitializedObject(typeof(T)); - Unsafe.As(ref Unsafe.As(box).Data) = value; - return box; + return RuntimeHelpers.Box(ref Unsafe.As(ref value), typeof(T).TypeHandle); } /// diff --git a/src/ExcelReader.Core/Reader/SheetDataReader.cs b/src/ExcelReader.Core/Reader/SheetDataReader.cs index 7693956c..e0ae6672 100644 --- a/src/ExcelReader.Core/Reader/SheetDataReader.cs +++ b/src/ExcelReader.Core/Reader/SheetDataReader.cs @@ -208,6 +208,7 @@ public Type GetFieldType(int i) return TypeOf(CurrentCell(i)); } + [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties)] private static Type TypeOf(Cell cell) { return cell.Type switch From ecc5e264361a3a7c6c7816fd0edaca1bbafce166 Mon Sep 17 00:00:00 2001 From: Gabriel Matte Date: Tue, 27 Oct 2026 21:15:12 -0300 Subject: [PATCH 11/19] perf(writer): hash a new shared string once, and skip the shards when no worker added one --- .../Writer/Internal/SharedStringTable.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/ExcelReader.Core/Writer/Internal/SharedStringTable.cs b/src/ExcelReader.Core/Writer/Internal/SharedStringTable.cs index c790aee7..0a8e9ff7 100644 --- a/src/ExcelReader.Core/Writer/Internal/SharedStringTable.cs +++ b/src/ExcelReader.Core/Writer/Internal/SharedStringTable.cs @@ -1,4 +1,5 @@ using System.Globalization; +using System.Runtime.InteropServices; using ExcelReader.Core.Reader.Xlsb; using ExcelReader.Core.Writer.Xlsb; @@ -19,6 +20,7 @@ internal sealed class SharedStringTable private readonly Dictionary.AlternateLookup> _serialSpan; private int _count; private int _uniqueCount; + private bool _sharded; internal SharedStringTable() { @@ -36,31 +38,29 @@ internal SharedStringTable() internal int GetOrAdd(string value) { _count++; - if (_serial.TryGetValue(value, out int index)) + ref int index = ref CollectionsMarshal.GetValueRefOrAddDefault(_serial, value, out bool exists); + if (!exists) { - return index; + index = SerialMiss(value); } - index = SerialMiss(value); - _serial.Add(value, index); return index; } internal int GetOrAdd(ReadOnlySpan value) { _count++; - if (_serialSpan.TryGetValue(value, out int index)) + ref int index = ref CollectionsMarshal.GetValueRefOrAddDefault(_serialSpan, value, out bool exists); + if (!exists) { - return index; + index = SerialMiss(value); } - index = SerialMiss(value); - _serialSpan.TryAdd(value, index); return index; } // Workers may have added it to a shard; a text new to both takes the next index. private int SerialMiss(ReadOnlySpan value) { - return ShardFor(value).SpanIndexes.TryGetValue(value, out int index) ? index : _uniqueCount++; + return _sharded && ShardFor(value).SpanIndexes.TryGetValue(value, out int index) ? index : _uniqueCount++; } /// Resolves a text from a parallel worker without counting the reference; see . @@ -79,6 +79,7 @@ internal int GetOrAddConcurrent(ReadOnlySpan value) } index = Interlocked.Increment(ref _uniqueCount) - 1; shard.SpanIndexes.TryAdd(value, index); + _sharded = true; return index; } } From 247a4971c311d4208223bd44f1fc49fa361cc0d8 Mon Sep 17 00:00:00 2001 From: Gabriel Matte Date: Tue, 27 Oct 2026 21:21:21 -0300 Subject: [PATCH 12/19] perf(generator): write a ReadOnlySpan member through WriteUtf8 instead of decoding it to a string --- src/ExcelReader.Generator/ExcelRowMapGenerator.cs | 9 +++------ tests/ExcelReader.Tests/Generator/GeneratorTests.cs | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/ExcelReader.Generator/ExcelRowMapGenerator.cs b/src/ExcelReader.Generator/ExcelRowMapGenerator.cs index e4881983..3ad7386e 100644 --- a/src/ExcelReader.Generator/ExcelRowMapGenerator.cs +++ b/src/ExcelReader.Generator/ExcelRowMapGenerator.cs @@ -365,7 +365,8 @@ private static PropertyPlan BuildPlan(List diagnostics, INamedTy { bool needsNullConditional = isNullable || !underlying.IsValueType; string valueExpr = WriteValueExpression(writeKind, needsNullConditional, member, underlying); - writeEmit = $" .Column({Literal(names[0])}, static (row, m) => row.Write({valueExpr}))"; + string writeMethod = writeKind == WriteKind.Utf8Text ? "WriteUtf8" : "Write"; + writeEmit = $" .Column({Literal(names[0])}, static (row, m) => row.{writeMethod}({valueExpr}))"; } } @@ -409,11 +410,7 @@ private static ReadKind SelectReadKind(bool isGuid, bool isNullable) private static string WriteValueExpression(WriteKind kind, bool needsNullConditional, string propertyName, ITypeSymbol underlying) { - if (kind == WriteKind.Utf8Text) - { - return $"global::System.Text.Encoding.UTF8.GetString(m.{propertyName})"; - } - if (kind == WriteKind.Direct) + if (kind is WriteKind.Utf8Text or WriteKind.Direct) { return $"m.{propertyName}"; } diff --git a/tests/ExcelReader.Tests/Generator/GeneratorTests.cs b/tests/ExcelReader.Tests/Generator/GeneratorTests.cs index 25a955f2..03f39e81 100644 --- a/tests/ExcelReader.Tests/Generator/GeneratorTests.cs +++ b/tests/ExcelReader.Tests/Generator/GeneratorTests.cs @@ -1031,7 +1031,7 @@ public ref partial struct Reading Assert.Contains("ref partial struct Reading : global::ExcelReader.Core.Parser.IExcelRowMap<", generated, StringComparison.Ordinal); Assert.Contains("global::ExcelReader.Core.Writer.IExcelRecordMap<", generated, StringComparison.Ordinal); Assert.Contains("global::ExcelReader.Core.Parser.ExcelCellReaders.Utf8(in c, in x, out global::System.ReadOnlySpan v)", generated, StringComparison.Ordinal); - Assert.Contains("row.Write(global::System.Text.Encoding.UTF8.GetString(m.Station))", generated, StringComparison.Ordinal); + Assert.Contains("row.WriteUtf8(m.Station)", generated, StringComparison.Ordinal); } } } From a0ccf7e25583bf6a0f01a8e64766db79f1694977 Mon Sep 17 00:00:00 2001 From: Gabriel Matte Date: Tue, 27 Oct 2026 21:21:21 -0300 Subject: [PATCH 13/19] perf(writer): format runtime value types in reflected records straight to UTF-8 --- .../Writer/Internal/RecordColumns.cs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/ExcelReader.Core/Writer/Internal/RecordColumns.cs b/src/ExcelReader.Core/Writer/Internal/RecordColumns.cs index 330217eb..f31ade07 100644 --- a/src/ExcelReader.Core/Writer/Internal/RecordColumns.cs +++ b/src/ExcelReader.Core/Writer/Internal/RecordColumns.cs @@ -2,6 +2,7 @@ using System.Globalization; using System.Linq.Expressions; using System.Reflection; +using System.Runtime.CompilerServices; using ExcelReader.Core.Parser; namespace ExcelReader.Core.Writer.Internal @@ -63,6 +64,22 @@ private static Expression ToStringExpression(Expression value, Type pt) Expression.Call(boxed, toString), Expression.Constant(null, typeof(string))); } + // Runtime value types (Guid, DateTimeOffset, TimeSpan...) format to the same text as UTF-8, without the string. + private static MethodCallExpression? TryBuildUtf8Write(ParameterExpression rowParam, Expression value, Type pt) + { + Type? underlying = Nullable.GetUnderlyingType(pt); + Type core = underlying ?? pt; + // char is left out: its UTF-8 TryFormat throws on a lone surrogate. + if (!core.IsValueType || core.Assembly != typeof(object).Assembly || core == typeof(char) + ||!typeof(IUtf8SpanFormattable).IsAssignableFrom(core) || !typeof(IFormattable).IsAssignableFrom(core)) + { + return null; + } + string helper = underlying is null ? nameof(InvariantText.WriteValue) : nameof(InvariantText.WriteNullable); + MethodInfo method = typeof(InvariantText).GetMethod(helper, BindingFlags.NonPublic | BindingFlags.Static)!.MakeGenericMethod(typeof(TRow), core); + return Expression.Call(method, rowParam, value); + } + private static MethodCallExpression? TryBuildConverterWrite( PropertyInfo prop, ParameterExpression rowParam, Expression value, Dictionary instances) { @@ -102,6 +119,11 @@ private static Action Build() continue; } MethodInfo write = RowWriteMethods.Select(prop.PropertyType, out bool asString); + if (asString && TryBuildUtf8Write(rowParam, value, prop.PropertyType) is { } utf8Write) + { + body.Add(utf8Write); + continue; + } if (asString) { value = ToStringExpression(value, prop.PropertyType); @@ -197,6 +219,32 @@ internal static string FormatValue(TValue value) return value.HasValue ? FormatValue(value.GetValueOrDefault()) : null; } + [SkipLocalsInit] + internal static void WriteValue(TRow row, TValue value) + where TRow : IRowWriter + where TValue : struct, IFormattable, IUtf8SpanFormattable + { + Span utf8 = stackalloc byte[128]; + if (value.TryFormat(utf8, out int written, typeof(TValue) == typeof(DateTimeOffset) ? "O" : default, CultureInfo.InvariantCulture)) + { + row.WriteUtf8(utf8[..written]); + return; + } + row.Write(FormatValue(value)); + } + + internal static void WriteNullable(TRow row, TValue? value) + where TRow : IRowWriter + where TValue : struct, IFormattable, IUtf8SpanFormattable + { + if (!value.HasValue) + { + row.Write((string?)null); + return; + } + WriteValue(row, value.GetValueOrDefault()); + } + internal static string? FormatReference(TValue? value) where TValue : class, IFormattable { From ef831b19af3d63923097406efd5aa1bf2faf1b20 Mon Sep 17 00:00:00 2001 From: Gabriel Matte Date: Tue, 27 Oct 2026 21:24:44 -0300 Subject: [PATCH 14/19] perf(writer): keep a worker's own string in the shared-string shards instead of copying it --- .../Writer/Internal/SharedStringTable.cs | 20 +++++++++++++------ .../Writer/Parallel/WorkerStringCache.cs | 20 +++++++++++++++---- .../Writer/Parallel/WorkerStringCacheTests.cs | 6 +++--- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/ExcelReader.Core/Writer/Internal/SharedStringTable.cs b/src/ExcelReader.Core/Writer/Internal/SharedStringTable.cs index 0a8e9ff7..81071581 100644 --- a/src/ExcelReader.Core/Writer/Internal/SharedStringTable.cs +++ b/src/ExcelReader.Core/Writer/Internal/SharedStringTable.cs @@ -64,7 +64,7 @@ private int SerialMiss(ReadOnlySpan value) } /// Resolves a text from a parallel worker without counting the reference; see . - internal int GetOrAddConcurrent(ReadOnlySpan value) + internal int GetOrAddConcurrent(ReadOnlySpan value, string? owned) { if (_serialSpan.TryGetValue(value, out int serial)) { @@ -73,13 +73,12 @@ internal int GetOrAddConcurrent(ReadOnlySpan value) Shard shard = ShardFor(value); lock (shard.Gate) { - if (shard.SpanIndexes.TryGetValue(value, out int index)) + ref int index = ref shard.Slot(value, owned, out bool exists); + if (!exists) { - return index; + index = Interlocked.Increment(ref _uniqueCount) - 1; + _sharded = true; } - index = Interlocked.Increment(ref _uniqueCount) - 1; - shard.SpanIndexes.TryAdd(value, index); - _sharded = true; return index; } } @@ -221,6 +220,15 @@ internal Shard() internal Dictionary.AlternateLookup> SpanIndexes { get; } internal Lock Gate { get; } = new(); + + internal ref int Slot(ReadOnlySpan value, string? owned, out bool exists) + { + if (owned is null) + { + return ref CollectionsMarshal.GetValueRefOrAddDefault(SpanIndexes, value, out exists); + } + return ref CollectionsMarshal.GetValueRefOrAddDefault(Indexes, owned, out exists); + } } } } diff --git a/src/ExcelReader.Core/Writer/Parallel/WorkerStringCache.cs b/src/ExcelReader.Core/Writer/Parallel/WorkerStringCache.cs index f4e91bbf..49bf97df 100644 --- a/src/ExcelReader.Core/Writer/Parallel/WorkerStringCache.cs +++ b/src/ExcelReader.Core/Writer/Parallel/WorkerStringCache.cs @@ -23,21 +23,33 @@ internal WorkerStringCache(SharedStringTable table) internal int GetOrAdd(string value) { - return GetOrAdd(value.AsSpan()); + return GetOrAdd(value, value); } internal int GetOrAdd(ReadOnlySpan value) + { + return GetOrAdd(value, null); + } + + // An owned string is stored as is; a span is copied into a new string only when it is kept. + private int GetOrAdd(ReadOnlySpan value, string? owned) { _references++; if (_spanIndexes.TryGetValue(value, out int index)) { return index; } - index = _table.GetOrAddConcurrent(value); - if (_indexes.Count < MaxEntries) + index = _table.GetOrAddConcurrent(value, owned); + if (_indexes.Count >= MaxEntries) { - _spanIndexes.TryAdd(value, index); + return index; + } + if (owned is not null) + { + _indexes.TryAdd(owned, index); + return index; } + _spanIndexes.TryAdd(value, index); return index; } diff --git a/tests/ExcelReader.Tests/Writer/Parallel/WorkerStringCacheTests.cs b/tests/ExcelReader.Tests/Writer/Parallel/WorkerStringCacheTests.cs index 8aacce49..dd593d64 100644 --- a/tests/ExcelReader.Tests/Writer/Parallel/WorkerStringCacheTests.cs +++ b/tests/ExcelReader.Tests/Writer/Parallel/WorkerStringCacheTests.cs @@ -50,8 +50,8 @@ public void A_Text_Added_By_One_Path_Should_Keep_Its_Index_On_The_Other() var table = new SharedStringTable(); int serialA = table.GetOrAdd("a"); - int concurrentA = table.GetOrAddConcurrent("a"); - int concurrentB = table.GetOrAddConcurrent("b"); + int concurrentA = table.GetOrAddConcurrent("a", "a"); + int concurrentB = table.GetOrAddConcurrent("b", owned: null); int serialB = table.GetOrAdd("b".AsSpan()); int serialC = table.GetOrAdd("c"); @@ -77,7 +77,7 @@ public void GetOrAddConcurrent_Should_Give_Every_Thread_The_Same_Dense_Indexes() for (int step = 0; step < texts; step++) { int i = (step * 7919 + thread * 104_729) % texts; - indexes[i] = table.GetOrAddConcurrent(values[i]); + indexes[i] = table.GetOrAddConcurrent(values[i], thread % 2 == 0 ? values[i] : null); } seen[thread] = indexes; }); From 3938f744026564810df86ff46dd037b7ef510045 Mon Sep 17 00:00:00 2001 From: GabrielMarquezMatte Date: Wed, 28 Oct 2026 10:29:41 -0300 Subject: [PATCH 15/19] refactor: apply ConfigureAwait(false) to asynchronous calls and improve code readability --- docs/snippets/Encryption.cs | 5 +- docs/snippets/Parsing.cs | 20 +-- docs/snippets/Reading.cs | 35 ++++-- docs/snippets/UntrustedInput.cs | 12 +- docs/snippets/Writing.cs | 117 ++++++++++++------ .../Writer/Internal/RecordColumns.cs | 2 +- .../Writer/Xls/XlsWorkbookWriter.cs | 5 +- .../Writer/Xlsb/XlsbWorkbookWriter.cs | 5 +- .../Writer/Xlsx/XlsxSheetWriter.cs | 6 +- .../Writer/Xlsx/XlsxWorkbookWriter.cs | 5 +- .../ParallelCsv/AggregateCsvModelTests.cs | 11 +- 11 files changed, 152 insertions(+), 71 deletions(-) diff --git a/docs/snippets/Encryption.cs b/docs/snippets/Encryption.cs index 8d7c2fb8..2000a921 100644 --- a/docs/snippets/Encryption.cs +++ b/docs/snippets/Encryption.cs @@ -64,14 +64,15 @@ internal static async Task Run() { #region encryption-write using var plain = new MemoryStream(); - await using (var workbook = XlsxWorkbookWriter.Create(plain, leaveOpen: true)) + var workbook = XlsxWorkbookWriter.Create(plain, leaveOpen: true); + await using (workbook.ConfigureAwait(false)) { // write sheets and rows as usual } plain.Position = 0; using var destination = File.Create("secret.xlsx"); - await Excel.EncryptPackageAsync(plain, destination, "hunter2"); + await Excel.EncryptPackageAsync(plain, destination, "hunter2").ConfigureAwait(false); #endregion } } diff --git a/docs/snippets/Parsing.cs b/docs/snippets/Parsing.cs index 72dc9112..fe5bf579 100644 --- a/docs/snippets/Parsing.cs +++ b/docs/snippets/Parsing.cs @@ -98,11 +98,14 @@ internal static async Task Run() } var changes = new[] { new ChangeRow { File = "README.md", LinesAdded = 12 } }; - await using var stream = File.Create("changes.xlsx"); - await using var writer = XlsxWorkbookWriter.Create(stream); // or XlsbWorkbookWriter / XlsWorkbookWriter / CsvWorkbookWriter - await using (var sheet = writer.AddSheet("Changes")) + var stream = File.Create("changes.xlsx"); + await using (stream.ConfigureAwait(false)) { - await sheet.WriteRecordsAsync(changes, ExcelRecordLayout.Generated()); + await using var writer = XlsxWorkbookWriter.Create(stream).ConfigureAwait(false); // or XlsbWorkbookWriter / XlsWorkbookWriter / CsvWorkbookWriter + await using (var sheet = writer.AddSheet("Changes").ConfigureAwait(false)) + { + await sheet.WriteRecordsAsync(changes, ExcelRecordLayout.Generated()).ConfigureAwait(false); + } } #endregion } @@ -279,12 +282,15 @@ internal static class Snippet internal static async Task Run() { #region parsing-ref-struct-async - await using var workbook = await Excel.FromXlsxFileAsync("changes.xlsx"); - - await foreach (ChangeRowRef item in ExcelParser.FromAttributes().Parse(workbook.FirstSheet)) + var workbook = await Excel.FromXlsxFileAsync("changes.xlsx").ConfigureAwait(false); + #region parsing-ref-struct-async + await using (workbook.ConfigureAwait(false)) + { + await foreach (ChangeRowRef item in ExcelParser.FromAttributes().Parse(workbook.FirstSheet).ConfigureAwait(false)) { Console.WriteLine($"{Encoding.UTF8.GetString(item.File)}: +{item.LinesAdded}"); } + } #endregion } } diff --git a/docs/snippets/Reading.cs b/docs/snippets/Reading.cs index fd91e128..898ec17b 100644 --- a/docs/snippets/Reading.cs +++ b/docs/snippets/Reading.cs @@ -46,7 +46,7 @@ internal static async Task Run() #region reading-parallel-parse using XlsxWorkbook workbook = Excel.FromXlsxFile("big.xlsx"); - await foreach (var row in SheetParallel.ParseAsync(workbook.FirstSheet, ExcelParser.FromAttributes(), new SheetParallelOptions { DegreeOfParallelism = 8 })) + await foreach (var row in SheetParallel.ParseAsync(workbook.FirstSheet, ExcelParser.FromAttributes(), new SheetParallelOptions { DegreeOfParallelism = 8 }).ConfigureAwait(false)) { Total += row.Revenue; } @@ -68,9 +68,15 @@ public sealed class UnitTotal : IRowAccumulator { public long Units; - public void Add(SaleRow model) => Units += model.Units; + public void Add(SaleRow model) + { + Units += model.Units; + } - public void Merge(UnitTotal following) => Units += following.Units; + public void Merge(UnitTotal following) + { + Units += following.Units; + } } #endregion @@ -84,7 +90,7 @@ internal static async Task Run() UnitTotal total = await SheetParallel.AggregateAsync( workbook.FirstSheet, ExcelParser.FromAttributes(), - new SheetParallelOptions { HeaderRow = 1 }); + new SheetParallelOptions { HeaderRow = 1 }).ConfigureAwait(false); #endregion } } @@ -106,7 +112,7 @@ await SheetParallel.ForEachAsync( workbook.FirstSheet, ExcelParser.FromAttributes(), row => Interlocked.Add(ref total, row.Units), - new SheetParallelOptions { DegreeOfParallelism = 8, HeaderRow = 1 }); + new SheetParallelOptions { DegreeOfParallelism = 8, HeaderRow = 1 }).ConfigureAwait(false); #endregion } } @@ -311,12 +317,15 @@ internal static class Snippet internal static async Task Run(CancellationToken cancellationToken) { #region reading-async - await using var workbook = await Excel.FromXlsxFileAsync("report.xlsx", ct: cancellationToken); - - await foreach (var row in workbook.FirstSheet) + var workbook = await Excel.FromXlsxFileAsync("report.xlsx", ct: cancellationToken).ConfigureAwait(false); + #region reading-async + await using (workbook.ConfigureAwait(false)) + { + await foreach (var row in workbook.FirstSheet.ConfigureAwait(false)) { Console.WriteLine(row[0].GetString()); } + } #endregion } } @@ -329,14 +338,18 @@ internal static class Snippet internal static async Task Run(CancellationToken cancellationToken) { #region reading-async-enumerator - await using var workbook = await Excel.FromXlsxFileAsync("report.xlsx", ct: cancellationToken); - await using var rows = workbook.FirstSheet.GetAsyncEnumerator(cancellationToken); + var workbook = await Excel.FromXlsxFileAsync("report.xlsx", ct: cancellationToken).ConfigureAwait(false); + #region reading-async-enumerator + await using (workbook.ConfigureAwait(false)) + { + await using var rows = workbook.FirstSheet.GetAsyncEnumerator(cancellationToken).ConfigureAwait(false); - while (await rows.MoveNextAsync()) + while (await rows.MoveNextAsync().ConfigureAwait(false)) { var row = rows.Current; Console.WriteLine(row[0].GetString()); } + } #endregion } } diff --git a/docs/snippets/UntrustedInput.cs b/docs/snippets/UntrustedInput.cs index c894b537..41f42d00 100644 --- a/docs/snippets/UntrustedInput.cs +++ b/docs/snippets/UntrustedInput.cs @@ -42,11 +42,13 @@ internal static void Run(Stream upload, ExcelReaderOptions uploadOptions) Console.WriteLine($"Rejected: {ex.Message}"); } - static bool IsRejectedFile(Exception ex) => - ex is InvalidDataException or EndOfStreamException or NotSupportedException + static bool IsRejectedFile(Exception ex) + { + return ex is InvalidDataException or EndOfStreamException or NotSupportedException or ExcelEncryptionException or ExcelParseException || ex.GetType() == typeof(ArgumentException) || ex.GetType() == typeof(InvalidOperationException); + } #endregion } } @@ -59,8 +61,10 @@ internal static class Snippet internal static void Run(CsvRowWriter row, string comment) { #region untrusted-input-csv-injection - static string Neutralize(string text) => - text.Length > 0 && "=+-@\t\r".Contains(text[0]) ? "'" + text : text; + static string Neutralize(string text) + { + return text.Length > 0 && "=+-@\t\r".Contains(text[0]) ? "'" + text : text; + } row.Write(Neutralize(comment)); #endregion diff --git a/docs/snippets/Writing.cs b/docs/snippets/Writing.cs index b2f8b115..08aa61a1 100644 --- a/docs/snippets/Writing.cs +++ b/docs/snippets/Writing.cs @@ -10,19 +10,22 @@ internal static class Snippet internal static async Task Run() { #region writing-xlsx - await using var stream = File.Create("out.xlsx"); - await using var workbook = XlsxWorkbookWriter.Create(stream); + var stream = File.Create("out.xlsx"); + #region writing-xlsx + await using (stream.ConfigureAwait(false)) + { + await using var workbook = XlsxWorkbookWriter.Create(stream).ConfigureAwait(false); - await using (var sheet = workbook.AddSheet("Summary")) + await using (var sheet = workbook.AddSheet("Summary").ConfigureAwait(false)) { - await using (var row = await sheet.StartRowAsync()) + await using (var row = (await sheet.StartRowAsync()).ConfigureAwait(false)) { row.Write("Name"); row.Write("Total"); row.Write("Created"); } - await using (var row = await sheet.StartRowAsync()) + await using (var row = (await sheet.StartRowAsync()).ConfigureAwait(false)) { row.Write("Q1"); row.Write(42); @@ -30,7 +33,8 @@ internal static async Task Run() } } - await workbook.EndAsync(); + await workbook.EndAsync().ConfigureAwait(false); + } #endregion } } @@ -43,7 +47,11 @@ internal static class Snippet internal static async Task Run(Stream stream) { #region writing-xlsx-shared-strings - await using var workbook = XlsxWorkbookWriter.Create(stream, options: new XlsxWriterOptions { UseSharedStrings = true }); + var workbook = XlsxWorkbookWriter.Create(stream, options: new XlsxWriterOptions { UseSharedStrings = true }); + #region writing-xlsx-shared-strings + await using (workbook.ConfigureAwait(false)) + { + } #endregion } } @@ -60,9 +68,13 @@ internal static class Snippet internal static async Task Run(XlsxWorkbookWriter workbook) { #region writing-hidden-sheets - await using (var data = workbook.AddSheet("Data")) { /* rows */ } // visible - await using (var lookups = workbook.AddSheet("Lookups", ExcelSheetVisibility.Hidden)) { /* rows */ } - await using (var audit = workbook.AddSheet("Audit", ExcelSheetVisibility.VeryHidden)) { /* rows */ } // not in Excel's unhide dialog + var data = workbook.AddSheet("Data"); + #region writing-hidden-sheets + await using (data.ConfigureAwait(false)) { /* rows */ } // visible + var lookups = workbook.AddSheet("Lookups", ExcelSheetVisibility.Hidden); + await using (lookups.ConfigureAwait(false)) { /* rows */ } + var audit = workbook.AddSheet("Audit", ExcelSheetVisibility.VeryHidden); + await using (audit.ConfigureAwait(false)) { /* rows */ } // not in Excel's unhide dialog #endregion } } @@ -80,27 +92,33 @@ internal static class Snippet internal static async Task Run(Stream stream) { #region writing-styles - await using var workbook = XlsxWorkbookWriter.Create(stream); - - int currency = workbook.AddStyle(new CellStyle { NumberFormat = "R$ #,##0.00" }); + var workbook = XlsxWorkbookWriter.Create(stream); + #region writing-styles + await using (workbook.ConfigureAwait(false)) + { + int currency = workbook.AddStyle(new CellStyle { NumberFormat = "R$ #,##0.00" }); int header = workbook.AddStyle(new CellStyle { Bold = true }); - await using var sheet = workbook.AddSheet("Summary"); + await using var sheet = workbook.AddSheet("Summary").ConfigureAwait(false); sheet.SetColumnStyle(columnIndex: 1, currency); // before the first row sheet.SetColumnWidth(columnIndex: 0, width: 20); - await using (var row = await sheet.StartRowAsync(header)) + await using (var row = (await sheet.StartRowAsync(header).ConfigureAwait(false)).ConfigureAwait(false)) { row.Write("Product"); row.Write("Total"); } - await using (var row = await sheet.StartRowAsync()) { - row.Write("Widget"); - row.Write(1234.5); + var row = await sheet.StartRowAsync().ConfigureAwait(false); + await using (row.ConfigureAwait(false)) + { + row.Write("Widget"); + row.Write(1234.5); + } } - await workbook.EndAsync(); + await workbook.EndAsync().ConfigureAwait(false); + } #endregion } } @@ -118,12 +136,15 @@ internal static class Snippet internal static async Task Run() { #region writing-xlsb - await using var stream = File.Create("out.xlsb"); - await using var workbook = XlsbWorkbookWriter.Create(stream); + var stream = File.Create("out.xlsb"); + #region writing-xlsb + await using (stream.ConfigureAwait(false)) + { + await using var workbook = XlsbWorkbookWriter.Create(stream).ConfigureAwait(false); - await using (XlsbSheetWriter sheet = workbook.AddSheet("Summary")) + await using (XlsbSheetWriter sheet = workbook.AddSheet("Summary").ConfigureAwait(false).ConfigureAwait(false)) { - await using (XlsbRowWriter row = await sheet.StartRowAsync()) + await using (XlsbRowWriter row = (await sheet.StartRowAsync().ConfigureAwait(false)).ConfigureAwait(false)) { row.Write("Name"); row.Write("Total"); @@ -131,7 +152,8 @@ internal static async Task Run() } } - await workbook.EndAsync(); + await workbook.EndAsync().ConfigureAwait(false); + } #endregion } } @@ -149,8 +171,11 @@ internal static class Snippet internal static async Task Run() { #region writing-xls - await using var stream = File.Create("out.xls"); - await using var workbook = XlsWorkbookWriter.Create(stream); + var stream = File.Create("out.xls"); + #region writing-xls + await using (stream.ConfigureAwait(false)) + { + await using var workbook = XlsWorkbookWriter.Create(stream).ConfigureAwait(false); using (var sheet = workbook.AddSheet("Summary")) { @@ -169,7 +194,8 @@ internal static async Task Run() } } - await workbook.EndAsync(); + await workbook.EndAsync().ConfigureAwait(false); + } #endregion } } @@ -203,11 +229,14 @@ internal static async Task Run() new Sale { Region = "South", Units = 17, Revenue = 512.00m, Date = new DateOnly(2026, 1, 3) }, }; - await using var stream = File.Create("sales.xlsx"); - await using var workbook = XlsxWorkbookWriter.Create(stream); // or XlsbWorkbookWriter / XlsWorkbookWriter / CsvWorkbookWriter - await using (var sheet = workbook.AddSheet("Sales")) + var stream = File.Create("sales.xlsx"); + await using (stream.ConfigureAwait(false)) + { + await using var workbook = XlsxWorkbookWriter.Create(stream).ConfigureAwait(false); // or XlsbWorkbookWriter / XlsWorkbookWriter / CsvWorkbookWriter + await using (var sheet = workbook.AddSheet("Sales").ConfigureAwait(false)) { - await sheet.WriteRecordsAsync(sales, ExcelRecordLayout.FromAttributes()); + await sheet.WriteRecordsAsync(sales, ExcelRecordLayout.FromAttributes()).ConfigureAwait(false); + } } #endregion } @@ -248,7 +277,7 @@ internal static class Snippet internal static async Task Run(XlsxSheetWriter sheet, Sale[] sales) { #region writing-table-records - await sheet.WriteTableAsync(sales, "Sales", ExcelRecordLayout.FromAttributes()); + await sheet.WriteTableAsync(sales, "Sales", ExcelRecordLayout.FromAttributes()).ConfigureAwait(false); #endregion } } @@ -263,8 +292,11 @@ internal static class Snippet internal static async Task Run(Stream stream, Metric[] records) { #region writing-prefetch - await using var wb = XlsxWorkbookWriter.Create(stream, leaveOpen: true, options: new XlsxWriterOptions { PrefetchWrite = true }); - XlsxSheetWriter sheet = wb.AddSheet("S1"); + var wb = XlsxWorkbookWriter.Create(stream, leaveOpen: true, options: new XlsxWriterOptions { PrefetchWrite = true }); + #region writing-prefetch + await using (wb.ConfigureAwait(false)) + { + XlsxSheetWriter sheet = wb.AddSheet("S1"); foreach (var record in records) { @@ -273,7 +305,8 @@ internal static async Task Run(Stream stream, Metric[] records) row.Write(record.Value); } - await sheet.EndAsync(); + await sheet.EndAsync().ConfigureAwait(false); + } #endregion } } @@ -288,20 +321,24 @@ internal static class Snippet internal static async Task Run(Stream stream, IEnumerable records) { #region writing-parallel - await using var wb = XlsxWorkbookWriter.Create(stream, leaveOpen: true); - XlsxSheetWriter sheet = wb.AddSheet("S1"); + var wb = XlsxWorkbookWriter.Create(stream, leaveOpen: true); + #region writing-parallel + await using (wb.ConfigureAwait(false)) + { + XlsxSheetWriter sheet = wb.AddSheet("S1"); // Header row from the layout, then one row per record. - await sheet.WriteRecordsParallelAsync(records, ExcelRecordLayout.FromAttributes()); + await sheet.WriteRecordsParallelAsync(records, ExcelRecordLayout.FromAttributes()).ConfigureAwait(false); // Or format each row yourself; this delegate runs on several threads at once. await sheet.WriteRecordsParallelAsync(records, static (XlsxRowWriter row, Metric record) => { row.Write(record.Name); row.Write(record.Value); - }, new ParallelWriteOptions { DegreeOfParallelism = 4 }); + }, new ParallelWriteOptions { DegreeOfParallelism = 4 }).ConfigureAwait(false); - await sheet.EndAsync(); + await sheet.EndAsync().ConfigureAwait(false); + } #endregion } } diff --git a/src/ExcelReader.Core/Writer/Internal/RecordColumns.cs b/src/ExcelReader.Core/Writer/Internal/RecordColumns.cs index f31ade07..4fe63f07 100644 --- a/src/ExcelReader.Core/Writer/Internal/RecordColumns.cs +++ b/src/ExcelReader.Core/Writer/Internal/RecordColumns.cs @@ -71,7 +71,7 @@ private static Expression ToStringExpression(Expression value, Type pt) Type core = underlying ?? pt; // char is left out: its UTF-8 TryFormat throws on a lone surrogate. if (!core.IsValueType || core.Assembly != typeof(object).Assembly || core == typeof(char) - ||!typeof(IUtf8SpanFormattable).IsAssignableFrom(core) || !typeof(IFormattable).IsAssignableFrom(core)) + || !typeof(IUtf8SpanFormattable).IsAssignableFrom(core) || !typeof(IFormattable).IsAssignableFrom(core)) { return null; } diff --git a/src/ExcelReader.Core/Writer/Xls/XlsWorkbookWriter.cs b/src/ExcelReader.Core/Writer/Xls/XlsWorkbookWriter.cs index 73c39d45..a8fdd19e 100644 --- a/src/ExcelReader.Core/Writer/Xls/XlsWorkbookWriter.cs +++ b/src/ExcelReader.Core/Writer/Xls/XlsWorkbookWriter.cs @@ -85,7 +85,10 @@ public int AddStyle(CellStyle style) internal int StyleCount => _styles.Count; - internal int DateStyle(int styleId) => _styles.DateVariant(styleId); + internal int DateStyle(int styleId) + { + return _styles.DateVariant(styleId); + } internal int AddSharedString(ReadOnlySpan value) { diff --git a/src/ExcelReader.Core/Writer/Xlsb/XlsbWorkbookWriter.cs b/src/ExcelReader.Core/Writer/Xlsb/XlsbWorkbookWriter.cs index 460b78c7..f32a9721 100644 --- a/src/ExcelReader.Core/Writer/Xlsb/XlsbWorkbookWriter.cs +++ b/src/ExcelReader.Core/Writer/Xlsb/XlsbWorkbookWriter.cs @@ -99,7 +99,10 @@ public int AddStyle(CellStyle style) internal int StyleCount => _styles.Count; - internal int DateStyle(int styleId) => _styles.DateVariant(styleId); + internal int DateStyle(int styleId) + { + return _styles.DateVariant(styleId); + } /// /// Synchronous counterpart to , for native/unmanaged callers whose ABI is diff --git a/src/ExcelReader.Core/Writer/Xlsx/XlsxSheetWriter.cs b/src/ExcelReader.Core/Writer/Xlsx/XlsxSheetWriter.cs index cfb19fbd..ccaf67e3 100644 --- a/src/ExcelReader.Core/Writer/Xlsx/XlsxSheetWriter.cs +++ b/src/ExcelReader.Core/Writer/Xlsx/XlsxSheetWriter.cs @@ -80,7 +80,11 @@ private static int DetachedCapacity(int batchRows) internal bool UseSharedStrings => _owner.UseSharedStrings; internal bool Date1904 => _owner.Date1904; - internal int DateStyle(int styleId) => _owner.DateStyle(styleId); + internal int DateStyle(int styleId) + { + return _owner.DateStyle(styleId); + } + internal bool ResourcesReleased => _stream is null && _rowBuffer.IsReleased; internal int GetSharedStringIndex(string value) diff --git a/src/ExcelReader.Core/Writer/Xlsx/XlsxWorkbookWriter.cs b/src/ExcelReader.Core/Writer/Xlsx/XlsxWorkbookWriter.cs index 602de252..ccb7387a 100644 --- a/src/ExcelReader.Core/Writer/Xlsx/XlsxWorkbookWriter.cs +++ b/src/ExcelReader.Core/Writer/Xlsx/XlsxWorkbookWriter.cs @@ -121,7 +121,10 @@ public int AddStyle(CellStyle style) internal int StyleCount => _styles.Count; - internal int DateStyle(int styleId) => _styles.DateVariant(styleId); + internal int DateStyle(int styleId) + { + return _styles.DateVariant(styleId); + } /// /// Synchronous counterpart to , for native/unmanaged callers whose ABI is diff --git a/tests/ExcelReader.Tests/Parser/ParallelCsv/AggregateCsvModelTests.cs b/tests/ExcelReader.Tests/Parser/ParallelCsv/AggregateCsvModelTests.cs index a476e06b..e2b72f5c 100644 --- a/tests/ExcelReader.Tests/Parser/ParallelCsv/AggregateCsvModelTests.cs +++ b/tests/ExcelReader.Tests/Parser/ParallelCsv/AggregateCsvModelTests.cs @@ -375,8 +375,15 @@ public override readonly int GetHashCode() return Last.GetHashCode(); } - public static bool operator ==(WideRow left, WideRow right) => left.Equals(right); - public static bool operator !=(WideRow left, WideRow right) => !left.Equals(right); + public static bool operator ==(WideRow left, WideRow right) + { + return left.Equals(right); + } + + public static bool operator !=(WideRow left, WideRow right) + { + return !left.Equals(right); + } } private sealed class WideLog : IRowAccumulator From 19ee60bd55eca0166310a35798810672779d30c4 Mon Sep 17 00:00:00 2001 From: GabrielMarquezMatte Date: Wed, 28 Oct 2026 10:32:26 -0300 Subject: [PATCH 16/19] refactor: improve code formatting and readability in Parsing, Reading, and Writing snippets --- docs/snippets/Parsing.cs | 15 ++-- docs/snippets/Reading.cs | 17 +++-- docs/snippets/Writing.cs | 149 +++++++++++++++++++-------------------- 3 files changed, 89 insertions(+), 92 deletions(-) diff --git a/docs/snippets/Parsing.cs b/docs/snippets/Parsing.cs index fe5bf579..66f9915c 100644 --- a/docs/snippets/Parsing.cs +++ b/docs/snippets/Parsing.cs @@ -102,10 +102,10 @@ internal static async Task Run() await using (stream.ConfigureAwait(false)) { await using var writer = XlsxWorkbookWriter.Create(stream).ConfigureAwait(false); // or XlsbWorkbookWriter / XlsWorkbookWriter / CsvWorkbookWriter - await using (var sheet = writer.AddSheet("Changes").ConfigureAwait(false)) - { - await sheet.WriteRecordsAsync(changes, ExcelRecordLayout.Generated()).ConfigureAwait(false); - } + await using (var sheet = writer.AddSheet("Changes").ConfigureAwait(false)) + { + await sheet.WriteRecordsAsync(changes, ExcelRecordLayout.Generated()).ConfigureAwait(false); + } } #endregion } @@ -283,13 +283,12 @@ internal static async Task Run() { #region parsing-ref-struct-async var workbook = await Excel.FromXlsxFileAsync("changes.xlsx").ConfigureAwait(false); - #region parsing-ref-struct-async await using (workbook.ConfigureAwait(false)) { await foreach (ChangeRowRef item in ExcelParser.FromAttributes().Parse(workbook.FirstSheet).ConfigureAwait(false)) - { - Console.WriteLine($"{Encoding.UTF8.GetString(item.File)}: +{item.LinesAdded}"); - } + { + Console.WriteLine($"{Encoding.UTF8.GetString(item.File)}: +{item.LinesAdded}"); + } } #endregion } diff --git a/docs/snippets/Reading.cs b/docs/snippets/Reading.cs index 898ec17b..0af55ab7 100644 --- a/docs/snippets/Reading.cs +++ b/docs/snippets/Reading.cs @@ -322,9 +322,9 @@ internal static async Task Run(CancellationToken cancellationToken) await using (workbook.ConfigureAwait(false)) { await foreach (var row in workbook.FirstSheet.ConfigureAwait(false)) - { - Console.WriteLine(row[0].GetString()); - } + { + Console.WriteLine(row[0].GetString()); + } } #endregion } @@ -337,18 +337,17 @@ internal static class Snippet { internal static async Task Run(CancellationToken cancellationToken) { - #region reading-async-enumerator var workbook = await Excel.FromXlsxFileAsync("report.xlsx", ct: cancellationToken).ConfigureAwait(false); #region reading-async-enumerator await using (workbook.ConfigureAwait(false)) { await using var rows = workbook.FirstSheet.GetAsyncEnumerator(cancellationToken).ConfigureAwait(false); - while (await rows.MoveNextAsync().ConfigureAwait(false)) - { - var row = rows.Current; - Console.WriteLine(row[0].GetString()); - } + while (await rows.MoveNextAsync().ConfigureAwait(false)) + { + var row = rows.Current; + Console.WriteLine(row[0].GetString()); + } } #endregion } diff --git a/docs/snippets/Writing.cs b/docs/snippets/Writing.cs index 08aa61a1..7f788e11 100644 --- a/docs/snippets/Writing.cs +++ b/docs/snippets/Writing.cs @@ -16,24 +16,24 @@ internal static async Task Run() { await using var workbook = XlsxWorkbookWriter.Create(stream).ConfigureAwait(false); - await using (var sheet = workbook.AddSheet("Summary").ConfigureAwait(false)) - { - await using (var row = (await sheet.StartRowAsync()).ConfigureAwait(false)) + await using (var sheet = workbook.AddSheet("Summary").ConfigureAwait(false)) { - row.Write("Name"); - row.Write("Total"); - row.Write("Created"); + await using (var row = (await sheet.StartRowAsync()).ConfigureAwait(false)) + { + row.Write("Name"); + row.Write("Total"); + row.Write("Created"); + } + + await using (var row = (await sheet.StartRowAsync()).ConfigureAwait(false)) + { + row.Write("Q1"); + row.Write(42); + row.Write(DateTime.UtcNow); + } } - await using (var row = (await sheet.StartRowAsync()).ConfigureAwait(false)) - { - row.Write("Q1"); - row.Write(42); - row.Write(DateTime.UtcNow); - } - } - - await workbook.EndAsync().ConfigureAwait(false); + await workbook.EndAsync().ConfigureAwait(false); } #endregion } @@ -97,27 +97,27 @@ internal static async Task Run(Stream stream) await using (workbook.ConfigureAwait(false)) { int currency = workbook.AddStyle(new CellStyle { NumberFormat = "R$ #,##0.00" }); - int header = workbook.AddStyle(new CellStyle { Bold = true }); + int header = workbook.AddStyle(new CellStyle { Bold = true }); - await using var sheet = workbook.AddSheet("Summary").ConfigureAwait(false); - sheet.SetColumnStyle(columnIndex: 1, currency); // before the first row - sheet.SetColumnWidth(columnIndex: 0, width: 20); + await using var sheet = workbook.AddSheet("Summary").ConfigureAwait(false); + sheet.SetColumnStyle(columnIndex: 1, currency); // before the first row + sheet.SetColumnWidth(columnIndex: 0, width: 20); - await using (var row = (await sheet.StartRowAsync(header).ConfigureAwait(false)).ConfigureAwait(false)) - { - row.Write("Product"); - row.Write("Total"); - } - { - var row = await sheet.StartRowAsync().ConfigureAwait(false); - await using (row.ConfigureAwait(false)) + await using (var row = (await sheet.StartRowAsync(header).ConfigureAwait(false)).ConfigureAwait(false)) { - row.Write("Widget"); - row.Write(1234.5); + row.Write("Product"); + row.Write("Total"); + } + { + var row = await sheet.StartRowAsync().ConfigureAwait(false); + await using (row.ConfigureAwait(false)) + { + row.Write("Widget"); + row.Write(1234.5); + } } - } - await workbook.EndAsync().ConfigureAwait(false); + await workbook.EndAsync().ConfigureAwait(false); } #endregion } @@ -142,17 +142,17 @@ internal static async Task Run() { await using var workbook = XlsbWorkbookWriter.Create(stream).ConfigureAwait(false); - await using (XlsbSheetWriter sheet = workbook.AddSheet("Summary").ConfigureAwait(false).ConfigureAwait(false)) - { - await using (XlsbRowWriter row = (await sheet.StartRowAsync().ConfigureAwait(false)).ConfigureAwait(false)) + await using (XlsbSheetWriter sheet = workbook.AddSheet("Summary").ConfigureAwait(false).ConfigureAwait(false)) { - row.Write("Name"); - row.Write("Total"); - row.Write("Created"); + await using (XlsbRowWriter row = (await sheet.StartRowAsync().ConfigureAwait(false)).ConfigureAwait(false)) + { + row.Write("Name"); + row.Write("Total"); + row.Write("Created"); + } } - } - await workbook.EndAsync().ConfigureAwait(false); + await workbook.EndAsync().ConfigureAwait(false); } #endregion } @@ -177,24 +177,24 @@ internal static async Task Run() { await using var workbook = XlsWorkbookWriter.Create(stream).ConfigureAwait(false); - using (var sheet = workbook.AddSheet("Summary")) - { - using (var row = sheet.StartRow()) - { - row.Write("Name"); - row.Write("Total"); - row.Write("Created"); - } - - using (var row = sheet.StartRow()) + using (var sheet = workbook.AddSheet("Summary")) { - row.Write("Q1"); - row.Write(42); - row.Write(DateTime.UtcNow); + using (var row = sheet.StartRow()) + { + row.Write("Name"); + row.Write("Total"); + row.Write("Created"); + } + + using (var row = sheet.StartRow()) + { + row.Write("Q1"); + row.Write(42); + row.Write(DateTime.UtcNow); + } } - } - await workbook.EndAsync().ConfigureAwait(false); + await workbook.EndAsync().ConfigureAwait(false); } #endregion } @@ -233,10 +233,10 @@ internal static async Task Run() await using (stream.ConfigureAwait(false)) { await using var workbook = XlsxWorkbookWriter.Create(stream).ConfigureAwait(false); // or XlsbWorkbookWriter / XlsWorkbookWriter / CsvWorkbookWriter - await using (var sheet = workbook.AddSheet("Sales").ConfigureAwait(false)) - { - await sheet.WriteRecordsAsync(sales, ExcelRecordLayout.FromAttributes()).ConfigureAwait(false); - } + await using (var sheet = workbook.AddSheet("Sales").ConfigureAwait(false)) + { + await sheet.WriteRecordsAsync(sales, ExcelRecordLayout.FromAttributes()).ConfigureAwait(false); + } } #endregion } @@ -298,14 +298,14 @@ internal static async Task Run(Stream stream, Metric[] records) { XlsxSheetWriter sheet = wb.AddSheet("S1"); - foreach (var record in records) - { - using XlsxRowWriter row = sheet.StartRow(); - row.Write(record.Name); - row.Write(record.Value); - } + foreach (var record in records) + { + using XlsxRowWriter row = sheet.StartRow(); + row.Write(record.Name); + row.Write(record.Value); + } - await sheet.EndAsync().ConfigureAwait(false); + await sheet.EndAsync().ConfigureAwait(false); } #endregion } @@ -320,24 +320,23 @@ internal static class Snippet { internal static async Task Run(Stream stream, IEnumerable records) { - #region writing-parallel var wb = XlsxWorkbookWriter.Create(stream, leaveOpen: true); #region writing-parallel await using (wb.ConfigureAwait(false)) { XlsxSheetWriter sheet = wb.AddSheet("S1"); - // Header row from the layout, then one row per record. - await sheet.WriteRecordsParallelAsync(records, ExcelRecordLayout.FromAttributes()).ConfigureAwait(false); + // Header row from the layout, then one row per record. + await sheet.WriteRecordsParallelAsync(records, ExcelRecordLayout.FromAttributes()).ConfigureAwait(false); - // Or format each row yourself; this delegate runs on several threads at once. - await sheet.WriteRecordsParallelAsync(records, static (XlsxRowWriter row, Metric record) => - { - row.Write(record.Name); - row.Write(record.Value); - }, new ParallelWriteOptions { DegreeOfParallelism = 4 }).ConfigureAwait(false); + // Or format each row yourself; this delegate runs on several threads at once. + await sheet.WriteRecordsParallelAsync(records, static (XlsxRowWriter row, Metric record) => + { + row.Write(record.Name); + row.Write(record.Value); + }, new ParallelWriteOptions { DegreeOfParallelism = 4 }).ConfigureAwait(false); - await sheet.EndAsync().ConfigureAwait(false); + await sheet.EndAsync().ConfigureAwait(false); } #endregion } From 6fbb0a6279677c01d43221ac9c2078f5bd8b2a74 Mon Sep 17 00:00:00 2001 From: GabrielMarquezMatte Date: Wed, 28 Oct 2026 11:17:44 -0300 Subject: [PATCH 17/19] perf(docs): update benchmark results for improved performance metrics across various formats --- cpp/README.md | 56 +++++++-------- docs/performance/benchmarks.md | 20 +++--- python/README.md | 73 ++++++++++---------- rust/excelreader/README.md | 26 +++---- src/ExcelReader.Native/pgo/excelreader.mibc | Bin 102906 -> 104895 bytes 5 files changed, 88 insertions(+), 87 deletions(-) diff --git a/cpp/README.md b/cpp/README.md index 9b5c79e2..86eb668f 100644 --- a/cpp/README.md +++ b/cpp/README.md @@ -526,13 +526,13 @@ on Windows 10 (22H2), 16 logical CPUs @ 3.39 GHz, MSVC 19.51 (Release), Google B | Benchmark | RealExcel.xlsb (100 rows) | 65K_Records_Data.xlsb (65,535 rows) | |---|---:|---:| -| `open` (from memory) | 23.4 µs | 1.17 ms | -| `parse` (4 or 6 bound columns) | 44.8 µs | 23.3 ms | -| `parse_batches`, batches of 1,000 / 10,000 rows | - | 22.4 ms / 22.9 ms | -| `infer_schema` (sample 100 / 1,000 rows) | 68.8 µs | 572.7 µs | +| `open` (from memory) | 22.7 µs | 1.23 ms | +| `parse` (4 or 6 bound columns) | 44.6 µs | 23.8 ms | +| `parse_batches`, batches of 1,000 / 10,000 rows | - | 22.6 ms / 23.1 ms | +| `infer_schema` (sample 100 / 1,000 rows) | 72.4 µs | 607.0 µs | `open` here is the byte-span overload, which copies the caller's buffer before returning (the caller may free -it afterwards), so it scales with file size: 1.17 ms is mostly copying the 3.7 MB fixture. Opening by +it afterwards), so it scales with file size: 1.23 ms is mostly copying the 3.7 MB fixture. Opening by path reads only the package directory and stays nearly flat — see the Rust suite below. `parse` scales linearly with rows × columns, at roughly 360 ns/row here. Draining the same sheet through the batched typed reader costs the same as one whole-sheet `parse` while holding @@ -549,12 +549,12 @@ sides decode every cell into an owned value (`std::string` for text, not the zer | Library | Mean | |---|---:| -| ExcelReader (`parse`) | 61.3 ms | -| DuckDB (`read_xlsx`, summing every column in SQL) | 413.8 ms | -| xlsxio (`xlsxioread_sheet_next_cell_*`) | 497.4 ms | -| xlnt (`worksheet::rows()` + `cell::to_string()`/`value()`) | 2,335.0 ms | +| ExcelReader (`parse`) | 58.0 ms | +| DuckDB (`read_xlsx`, summing every column in SQL) | 417.8 ms | +| xlsxio (`xlsxioread_sheet_next_cell_*`) | 515.5 ms | +| xlnt (`worksheet::rows()` + `cell::to_string()`/`value()`) | 2,495.0 ms | -ExcelReader is ~6.7x faster than DuckDB, ~8.1x faster than xlsxio and ~38x faster than xlnt on this +ExcelReader is ~7.2x faster than DuckDB, ~8.9x faster than xlsxio and ~43x faster than xlnt on this workload. xlsxio is a lean, purpose-built C streaming reader — the same abstraction level as ExcelReader's own native core — so it was the strongest of the two competitors tested, though still well behind. @@ -594,11 +594,11 @@ Measured on the same machine as above, GCC 16.2.0 (MSYS2 UCRT64, `-O3 -mavx2` fo | Workload | ExcelReader | zsv `compat` | zsv `fast` | |---|---:|---:|---:| -| Typed, 14 columns into `FullRow` | 27.4 ms | 22.6 ms | 20.0 ms | -| Cells, byte count | 11.6 ms | 5.8 ms | 3.5 ms | +| Typed, 14 columns into `FullRow` | 28.1 ms | 24.0 ms | 21.2 ms | +| Cells, byte count | 11.8 ms | 5.8 ms | 3.5 ms | -**zsv is faster on both.** Typed, it is ~1.2x (`compat`) and ~1.4x (`fast`) faster than ExcelReader. -Counting cells, it is ~2.0x and ~3.3x faster. +**zsv is faster on both.** Typed, it is ~1.2x (`compat`) and ~1.3x (`fast`) faster than ExcelReader. +Counting cells, it is ~2.0x and ~3.4x faster. The cells gap is the C ABI, not the CSV parser. `xl_rows_next_view` copies every cell's value into a native row the cursor owns, one call per row, and that alone costs ~10.6 ms here (calling it without @@ -635,11 +635,11 @@ is handed buffers that are already columnar, while `BM_WriteSheet` starts from a | Benchmark | Time | Rows/s | |---|---:|---:| -| `BM_WriteColumns` (pre-transposed) | 33.2 ms | 1.98 M/s | -| `BM_WriteSheet` (from `std::vector`) | 40.3 ms | 1.63 M/s | +| `BM_WriteColumns` (pre-transposed) | 34.0 ms | 1.94 M/s | +| `BM_WriteSheet` (from `std::vector`) | 39.9 ms | 1.64 M/s | -The transpose costs ~21% here. It is not free, but it is not the dominant cost of producing the -file — see the comparison below, where the same two cases over 14 columns land within ~14–16%. +The transpose costs ~17% here. It is not free, but it is not the dominant cost of producing the +file — see the comparison below, where the same two cases over 14 columns land within ~16–17%. `excelreader_cpp_write_compare_benchmarks` (under `-DEXCELREADER_BUILD_BENCHMARKS_COMPARE=ON`) puts that against xlnt, xlsxio and [DuckDB](https://github.com/duckdb/duckdb)'s `excel` extension, all @@ -656,12 +656,12 @@ competitor. | Library | Wall | CPU | |---|---:|---:| -| ExcelReader (`xl::write_columns`, pre-transposed) | 64.2–66.9 ms | 63.9–68.2 ms | -| ExcelReader (`xl::write_sheet`) | 74.8–76.0 ms | 74.7–76.4 ms | -| DuckDB (`COPY ... TO ... WITH (FORMAT xlsx)`) | 831.4–831.6 ms | 828.1 ms | -| libxlsxwriter (`worksheet_write_string`/`_number`) | 1,206.7 ms | 1,187.5 ms | -| xlsxio (`xlsxiowrite_add_cell_*`) | 2,405.1 ms | 1,125.0 ms | -| xlnt (`worksheet::cell().value()` + `save()`) | 5,525.3 ms | 5,515.6 ms | +| ExcelReader (`xl::write_columns`, pre-transposed) | 65.3–65.7 ms | 65.3–66.8 ms | +| ExcelReader (`xl::write_sheet`) | 76.2–76.5 ms | 76.4 ms | +| DuckDB (`COPY ... TO ... WITH (FORMAT xlsx)`) | 834.6–834.9 ms | 828.1–843.8 ms | +| libxlsxwriter (`worksheet_write_string`/`_number`) | 1,200.4 ms | 1,203.1 ms | +| xlsxio (`xlsxiowrite_add_cell_*`) | 2,441.4 ms | 859.4 ms | +| xlnt (`worksheet::cell().value()` + `save()`) | 5,554.0 ms | 5,546.9 ms | Same machine as above; Google Benchmark's own iteration counts, no `--benchmark_repetitions` (each iteration writes a whole 65,535-row file, so the slower cases run once or a handful of times). xlnt @@ -672,7 +672,7 @@ sampling within one run. `write_sheet` — the matched-work number, since it starts from the same `std::vector` every competitor is handed — is ~11x faster than DuckDB, ~16x faster than libxlsxwriter, ~32x -faster than xlsxio, and ~74x faster than xlnt on wall time. +faster than xlsxio, and ~73x faster than xlnt on wall time. ### Known issue: xlsxio + libxlsxwriter cannot share a binary @@ -709,10 +709,10 @@ Caveats, none of them optional when quoting these: - **xlsxio's CPU time is not stable across runs.** It read 843.8–906.3 ms before the fix (some runs missing the workbook.xml entry), 1,171.9 ms and 687.5 ms in the two runs after it, - 1,015.6 ms and 843.8 ms in the next two, 953.1 ms in the one after and 1,125.0 ms in the latest, while its wall time stayed at ~2.4 s throughout. Its wall time is dominated by I/O wait — + 1,015.6 ms and 843.8 ms in the next two, 953.1 ms in the one after, 1,125.0 ms in the next and 859.4 ms in the latest, while its wall time stayed at ~2.4 s throughout. Its wall time is dominated by I/O wait — CPU is well under half of wall, against every other case here being CPU-bound (wall ≈ CPU) — so quote the wall-time ratio, which is what a caller waits. Against this run's CPU time the gap from - `write_sheet` to xlsxio is ~15x, not ~32x. + `write_sheet` to xlsxio is ~11x, not ~32x. - **ExcelReader does slightly more work here**, not less: it attaches a number format to the two date columns so Excel shows a date, while every competitor case writes those as bare serial numbers. That difference favours the competitors. @@ -724,6 +724,6 @@ Caveats, none of them optional when quoting these: a full analytical query engine doing far more than any Excel-writing library here; this measures one narrow slice of it, not "DuckDB" as a whole. -The two ExcelReader cases land within ~14–16% of each other. The transpose's share grew as producing +The two ExcelReader cases land within ~16–17% of each other. The transpose's share grew as producing the file got cheaper, but it is still a minority of the cost. Reach for `write_columns` when your data is already columnar, but `write_sheet` is not the slow path. diff --git a/docs/performance/benchmarks.md b/docs/performance/benchmarks.md index 42a0a6f9..1c289013 100644 --- a/docs/performance/benchmarks.md +++ b/docs/performance/benchmarks.md @@ -447,23 +447,23 @@ zero-copy advantage the other can't take: | Comparison | Format | ExcelReader | Competitor | Ratio | |---|---|---:|---:|---:| -| vs. [calamine](https://github.com/tafia/calamine) (Rust) | XLSX | 72.3 ms | 271.2 ms | ~3.8x faster | -| vs. calamine (Rust) | XLSB | 46.3 ms | 82.9 ms | ~1.8x faster | -| vs. [DuckDB](https://github.com/duckdb/duckdb) `read_xlsx` (C++) | XLSX | 61.3 ms | 413.8 ms | ~6.7x faster | -| vs. [xlsxio](https://github.com/brechtsanders/xlsxio) (C) | XLSX | 61.3 ms | 497.4 ms | ~8.1x faster | -| vs. [xlnt](https://github.com/tfussell/xlnt) (C++) | XLSX | 61.3 ms | 2,335.0 ms | ~38x faster | -| vs. [zsv](https://github.com/liquidaty/zsv) `fast` engine (C) | CSV | 27.4 ms | 20.0 ms | ~1.4x **slower** | +| vs. [calamine](https://github.com/tafia/calamine) (Rust) | XLSX | 69.5 ms | 276.4 ms | ~4.0x faster | +| vs. calamine (Rust) | XLSB | 47.8 ms | 87.0 ms | ~1.8x faster | +| vs. [DuckDB](https://github.com/duckdb/duckdb) `read_xlsx` (C++) | XLSX | 58.0 ms | 417.8 ms | ~7.2x faster | +| vs. [xlsxio](https://github.com/brechtsanders/xlsxio) (C) | XLSX | 58.0 ms | 515.5 ms | ~8.9x faster | +| vs. [xlnt](https://github.com/tfussell/xlnt) (C++) | XLSX | 58.0 ms | 2,495.0 ms | ~43x faster | +| vs. [zsv](https://github.com/liquidaty/zsv) `fast` engine (C) | CSV | 28.1 ms | 21.2 ms | ~1.3x **slower** | Writing the same 14 columns × 65,535 rows from row-shaped data, the C++ suite measures -`write_sheet` at 74.8–76.0 ms against DuckDB's 831 ms (~11x), libxlsxwriter's 1,207 ms (~16x), -xlsxio's 2,405 ms (~32x) and xlnt's 5,525 ms (~74x). The Rust suite measures 40.7 ms against -rust_xlsxwriter's 322.0 ms (~7.9x) over 7 columns. Caveats for both are in the binding READMEs. +`write_sheet` at 76.2–76.5 ms against DuckDB's 835 ms (~11x), libxlsxwriter's 1,200 ms (~16x), +xlsxio's 2,441 ms (~32x) and xlnt's 5,554 ms (~73x). The Rust suite measures 40.8 ms against +rust_xlsxwriter's 338.5 ms (~8.3x) over 7 columns. Caveats for both are in the binding READMEs. DuckDB, xlsxio and xlnt do not read `.xlsb`, so those comparisons are XLSX-only. calamine is a fast, well-optimized reader in its own right — the gap there is real but not the order of magnitude seen against the C/C++ competitors. zsv is the one competitor ahead. The CSV row is the typed workload, where both sides build the same -14-column rows with owned strings. Just counting cell bytes, zsv is ~3.3x faster, and that gap is +14-column rows with owned strings. Just counting cell bytes, zsv is ~3.4x faster, and that gap is ExcelReader's C ABI, which serializes every row into a buffer, not its CSV parser. That suite is built with GCC (zsv does not compile under MSVC). Its caveats are in the C++ README. diff --git a/python/README.md b/python/README.md index e4e231fe..fdf2424b 100644 --- a/python/README.md +++ b/python/README.md @@ -129,7 +129,7 @@ A sheet reads in one of these shapes: `rows()` hands back cell *text*, which means the library formats every value to a string on the way out and builds one Python object per cell. `parse()` skips that entirely: you give it a schema, and the conversion happens natively, straight into typed column buffers. On a 65,536 × 14 sheet it is -~30× faster than `rows()`, and faster than `polars.read_excel()` — see [Reading](#reading) below for +~20× faster than `rows()`, and faster than `polars.read_excel()` — see [Reading](#reading) below for the measured numbers. ```python @@ -581,45 +581,46 @@ encrypt_package(plain, secret, "hunter2") `tests/ExcelReader.Benchmarks/Data/65K_Records_Data.xlsb` (65,535 data rows, 14 columns), the same fixture the .NET, C++ and Rust suites use. Measured on Windows 10 (22H2), AMD Ryzen 7 5700X (16 logical CPUs @ 3.39 GHz), CPython 3.14.7, 10 runs each (medians shown; `min` is in the scripts' own -output), against a library published from commit 449ca144. Competitors: polars 1.44.1 (with -fastexcel 0.21.0), pandas 3.0.5 (with openpyxl 3.1.5), xlsxwriter 3.2.9. +output), against a library published from commit ef831b19. Competitors: polars 2.0.0 (with +fastexcel 0.21.0), pandas 3.1.0 (with openpyxl 3.1.5), xlsxwriter 3.2.9. ### Reading | API | Median | What it produces | |---|---:|---| -| `to_arrow_stream()`, read by pyarrow | 31.2 ms | Arrow record batches, streamed | -| `to_arrow()` | 30.1 ms | the same parse, handed to pyarrow zero-copy | -| `parse()` | 32.5 ms | typed columnar buffers, converted natively | -| `parse_batches()` | 33.2 ms | the same typed buffers, in batches | -| `to_polars()` | 33.6 ms | typed columnar DataFrame, schema inferred | -| `polars.read_excel()` | 120.6 ms | typed columnar DataFrame, types inferred | -| `rows()` | 975.7 ms | one `Cell` object per cell, streamed per row | +| `to_arrow()` | 31.2 ms | the same parse, handed to pyarrow zero-copy | +| `to_arrow_stream()`, read by pyarrow | 32.0 ms | Arrow record batches, streamed | +| `parse()` | 33.8 ms | typed columnar buffers, converted natively | +| `parse_batches()` | 34.9 ms | the same typed buffers, in batches | +| `to_polars()` | 35.4 ms | typed columnar DataFrame, schema inferred | +| `polars.read_excel()` | 135.0 ms | typed columnar DataFrame, types inferred | +| `rows()` | 693.8 ms | one `Cell` object per cell, streamed per row | The batched readers cost the same as their whole-sheet counterparts and lower the peak memory: -`to_arrow_stream(batch_size=10000)` peaks at 11.4 MiB against 19.5 MiB for one whole-sheet +`to_arrow_stream(batch_size=10000)` peaks at 10.9 MiB against 19.4 MiB for one whole-sheet record batch on this file. -Only the `to_polars()` / `polars.read_excel()` pair is a like-for-like comparison (~3.6x), and even +Only the `to_polars()` / `polars.read_excel()` pair is a like-for-like comparison (~3.8x), and even that one is loose: both produce a typed columnar DataFrame with inferred types, but the inference rules are not identical. The rows above it produce different things and are listed to show what each API -costs, not to rank them — `rows()` is ~30x slower than `parse()` because it materializes +costs, not to rank them — `rows()` is ~20x slower than `parse()` because it materializes 917,504 Python objects, which is the price of that shape, not a slow parser. CSV, from `65K_Records_Data.csv` (8.2 MB), same 14 typed columns: | API | Median | |---|---:| -| `parse(parallelism=1)` | 23.3 ms | -| `parse(parallelism=0)` | 11.3 ms | -| `to_polars(parallelism=1)` | 24.2 ms | -| `to_polars(parallelism=0)` | 9.7 ms | -| `polars.read_csv(try_parse_dates=True)` | 6.9 ms | -| `pandas.read_csv`, pyarrow engine | 116.0 ms | -| `pandas.read_csv`, C engine | 132.3 ms | - -polars' CSV reader is ahead (multithreaded, and it infers types from the text without our schema -step); ExcelReader is ~10x faster than pandas on either engine. These include opening the file, so +| `parse(parallelism=1)` | 25.8 ms | +| `parse(parallelism=0)` | 13.7 ms | +| `to_polars(parallelism=1)` | 25.3 ms | +| `to_polars(parallelism=0)` | 11.3 ms | +| `polars.read_csv(try_parse_dates=True)` | 12.9 ms | +| `pandas.read_csv`, pyarrow engine | 114.5 ms | +| `pandas.read_csv`, C engine | 73.0 ms | + +At `parallelism=0` ExcelReader and polars' multithreaded CSV reader are level (`to_polars()` 11.3 ms +against 12.9 ms; polars infers types from the text, we convert against a given schema). ExcelReader is +~5x faster than pandas' C engine and ~8x faster than its pyarrow engine, measured with `parse(parallelism=0)`. These include opening the file, so they are above the in-memory `xl_parse_typed` figures in [Reading a large sheet on several threads](#reading-a-large-sheet-on-several-threads). @@ -627,28 +628,28 @@ threads](#reading-a-large-sheet-on-several-threads). | API | Median | Output | |---|---:|---| -| `write_workbook()` → csv | 33.3 ms | 8.2 MB | -| `write_workbook()` → xlsb | 51.7 ms | 4.5 MB | -| `write_workbook()` → xls | 59.2 ms | 13.4 MB | -| `write_workbook()` → xlsx | 68.5 ms | 5.1 MB | -| `write_workbook(polars_df)` → xlsx | 76.6 ms | 5.1 MB | -| `write_workbook(pandas_df)` → xlsx | 82.5 ms | 5.1 MB | -| `polars.DataFrame.write_excel()` | 4,714.9 ms | 5.6 MB | -| `pandas.DataFrame.to_excel()` | 7,371.4 ms | 5.5 MB | +| `write_workbook()` → csv | 35.9 ms | 8.2 MB | +| `write_workbook()` → xls | 53.0 ms | 13.4 MB | +| `write_workbook()` → xlsb | 53.7 ms | 4.5 MB | +| `write_workbook()` → xlsx | 68.8 ms | 5.1 MB | +| `write_workbook(polars_df)` → xlsx | 76.1 ms | 5.1 MB | +| `write_workbook(pandas_df)` → xlsx | 82.4 ms | 5.1 MB | +| `polars.DataFrame.write_excel()` | 4,754.8 ms | 5.6 MB | +| `pandas.DataFrame.to_excel()` | 7,696.4 ms | 5.5 MB | The two DataFrame comparisons are matched work — same DataFrame in, xlsx out both times: `write_workbook(polars_df)` is ~62x faster than polars' own `write_excel()`, and -`write_workbook(pandas_df)` ~89x faster than `to_excel()`. Both of ours pay a conversion the raw path does not: the DataFrame goes +`write_workbook(pandas_df)` ~93x faster than `to_excel()`. Both of ours pay a conversion the raw path does not: the DataFrame goes through Arrow, and each column is cast to the layout the native side reads and copied out of Arrow's -buffers, which is the gap between those rows and the 68.5 ms one. Handing `write_workbook()` buffers +buffers, which is the gap between those rows and the 68.8 ms one. Handing `write_workbook()` buffers that are already columnar — what `parse()` returns — skips it. -`write_workbook(xlsx)` at 68.5 ms lands within ~4 ms of the C++ binding's -`xl::write_columns` on the same 14 columns (64.2 ms), which is the expected result: both are thin wrappers +`write_workbook(xlsx)` at 68.8 ms lands within ~3 ms of the C++ binding's +`xl::write_columns` on the same 14 columns (65.7 ms), which is the expected result: both are thin wrappers over the same `xl_write_typed` call, and neither adds work per cell. `xls` being the largest file and still faster than xlsx is not a paradox — BIFF8 writes -fixed-width records with no compression, so it trades ~2.6x the bytes for less work per cell. xlsb is faster still, at 51.7 ms. +fixed-width records with no compression, so it trades ~2.6x the bytes for less work per cell. xlsb costs about the same, at 53.7 ms. ## Notes diff --git a/rust/excelreader/README.md b/rust/excelreader/README.md index 2ecd4d47..90ad71c0 100644 --- a/rust/excelreader/README.md +++ b/rust/excelreader/README.md @@ -617,12 +617,12 @@ takes 20 samples instead — each of its iterations writes a whole 65,535-row fi | Benchmark | RealExcel.xlsb (100 rows) | 65K_Records_Data.xlsb (65,535 rows) | |---|---:|---:| -| `open` | 85.8 µs | 99.4 µs | -| `parse_sheet` (2 or 6 bound columns) | 54.7 µs | 24.0 ms | -| typed chunks of 1,000 / 10,000 rows | - | 22.8 ms / 22.9 ms | -| `infer_schema` (sample 100 / 1,000 rows) | 83.9 µs | 571.0 µs | +| `open` | 90.5 µs | 102.1 µs | +| `parse_sheet` (2 or 6 bound columns) | 57.9 µs | 24.9 ms | +| typed chunks of 1,000 / 10,000 rows | - | 23.4 ms / 23.4 ms | +| `infer_schema` (sample 100 / 1,000 rows) | 89.7 µs | 611.1 µs | -`open` stays nearly flat across the 655x row-count jump (+16%) - XLSB's header carries its +`open` stays nearly flat across the 655x row-count jump (+13%) - XLSB's header carries its dimensions/index, so opening costs metadata, not row data. `parse_sheet` scales linearly with rows × columns. Reading the same sheet in typed chunks costs no more than one whole-sheet `parse_sheet`, while holding only one chunk at a time. `infer_schema` scales with its sample size, @@ -635,10 +635,10 @@ zero-copy advantage the other can't take: | Format | ExcelReader (`Sheet::parse::`) | calamine (`worksheet_range` + `Data` match) | |---|---:|---:| -| XLSX | 72.3 ms | 271.2 ms | -| XLSB | 46.3 ms | 82.9 ms | +| XLSX | 69.5 ms | 276.4 ms | +| XLSB | 47.8 ms | 87.0 ms | -ExcelReader is ~3.8x faster than calamine for XLSX and ~1.8x faster for XLSB on this workload - +ExcelReader is ~4.0x faster than calamine for XLSX and ~1.8x faster for XLSB on this workload - calamine is a fast, well-optimized reader in its own right, so the gap is real but not the order of magnitude seen against slower libraries. @@ -648,15 +648,15 @@ rows to `.xlsx`, all three starting from the same in-memory `Vec`: | Benchmark | Median | |---|---:| -| `columns` (`write_columns`, pre-transposed) | 33.8 ms | -| `sheet` (`write_sheet`, from `Vec`) | 40.7 ms | -| `rust_xlsxwriter` (cell-at-a-time) | 322.0 ms | +| `columns` (`write_columns`, pre-transposed) | 35.0 ms | +| `sheet` (`write_sheet`, from `Vec`) | 40.8 ms | +| `rust_xlsxwriter` (cell-at-a-time) | 338.5 ms | `sheet` is the matched-work number — it starts from the same shape `rust_xlsxwriter` is handed and -pays the row-to-column transpose itself — and is ~7.9x faster. `columns` is a ceiling no +pays the row-to-column transpose itself — and is ~8.3x faster. `columns` is a ceiling no cell-at-a-time API can reach, since it is handed buffers that are already columnar; read it only against `sheet`, as the cost of having row-shaped data in the first place. That cost turns out to be -about 21%: not free, but a minority of the cost of producing the file. +about 17%: not free, but a minority of the cost of producing the file. Two caveats, both running against the headline number rather than for it. ExcelReader does slightly *more* work here: it attaches a number format to the date column so Excel shows a date, and writes a diff --git a/src/ExcelReader.Native/pgo/excelreader.mibc b/src/ExcelReader.Native/pgo/excelreader.mibc index d9c38b97217cc276fdd628c945103c0d550bd97b..b07c17ed8a2ab0e523124204cc7315968a6266ef 100644 GIT binary patch literal 104895 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
  • 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 literal 102906 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

    T&_Y$uSWQ0rk>C6kt=jBIziLP% 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 From 2f7f1c600c9cdcd7362c25d0ef6ddee0b02d6348 Mon Sep 17 00:00:00 2001 From: GabrielMarquezMatte Date: Wed, 28 Oct 2026 13:24:37 -0300 Subject: [PATCH 18/19] refactor: streamline asynchronous resource management and improve code readability in Parsing, Reading, and Writing snippets --- docs/snippets/Parsing.cs | 21 ++-- docs/snippets/Reading.cs | 42 +++----- docs/snippets/Writing.cs | 212 ++++++++++++++++----------------------- 3 files changed, 111 insertions(+), 164 deletions(-) diff --git a/docs/snippets/Parsing.cs b/docs/snippets/Parsing.cs index 66f9915c..72dc9112 100644 --- a/docs/snippets/Parsing.cs +++ b/docs/snippets/Parsing.cs @@ -98,14 +98,11 @@ internal static async Task Run() } var changes = new[] { new ChangeRow { File = "README.md", LinesAdded = 12 } }; - var stream = File.Create("changes.xlsx"); - await using (stream.ConfigureAwait(false)) + await using var stream = File.Create("changes.xlsx"); + await using var writer = XlsxWorkbookWriter.Create(stream); // or XlsbWorkbookWriter / XlsWorkbookWriter / CsvWorkbookWriter + await using (var sheet = writer.AddSheet("Changes")) { - await using var writer = XlsxWorkbookWriter.Create(stream).ConfigureAwait(false); // or XlsbWorkbookWriter / XlsWorkbookWriter / CsvWorkbookWriter - await using (var sheet = writer.AddSheet("Changes").ConfigureAwait(false)) - { - await sheet.WriteRecordsAsync(changes, ExcelRecordLayout.Generated()).ConfigureAwait(false); - } + await sheet.WriteRecordsAsync(changes, ExcelRecordLayout.Generated()); } #endregion } @@ -282,13 +279,11 @@ internal static class Snippet internal static async Task Run() { #region parsing-ref-struct-async - var workbook = await Excel.FromXlsxFileAsync("changes.xlsx").ConfigureAwait(false); - await using (workbook.ConfigureAwait(false)) + await using var workbook = await Excel.FromXlsxFileAsync("changes.xlsx"); + + await foreach (ChangeRowRef item in ExcelParser.FromAttributes().Parse(workbook.FirstSheet)) { - await foreach (ChangeRowRef item in ExcelParser.FromAttributes().Parse(workbook.FirstSheet).ConfigureAwait(false)) - { - Console.WriteLine($"{Encoding.UTF8.GetString(item.File)}: +{item.LinesAdded}"); - } + Console.WriteLine($"{Encoding.UTF8.GetString(item.File)}: +{item.LinesAdded}"); } #endregion } diff --git a/docs/snippets/Reading.cs b/docs/snippets/Reading.cs index 0af55ab7..fd91e128 100644 --- a/docs/snippets/Reading.cs +++ b/docs/snippets/Reading.cs @@ -46,7 +46,7 @@ internal static async Task Run() #region reading-parallel-parse using XlsxWorkbook workbook = Excel.FromXlsxFile("big.xlsx"); - await foreach (var row in SheetParallel.ParseAsync(workbook.FirstSheet, ExcelParser.FromAttributes(), new SheetParallelOptions { DegreeOfParallelism = 8 }).ConfigureAwait(false)) + await foreach (var row in SheetParallel.ParseAsync(workbook.FirstSheet, ExcelParser.FromAttributes(), new SheetParallelOptions { DegreeOfParallelism = 8 })) { Total += row.Revenue; } @@ -68,15 +68,9 @@ public sealed class UnitTotal : IRowAccumulator { public long Units; - public void Add(SaleRow model) - { - Units += model.Units; - } + public void Add(SaleRow model) => Units += model.Units; - public void Merge(UnitTotal following) - { - Units += following.Units; - } + public void Merge(UnitTotal following) => Units += following.Units; } #endregion @@ -90,7 +84,7 @@ internal static async Task Run() UnitTotal total = await SheetParallel.AggregateAsync( workbook.FirstSheet, ExcelParser.FromAttributes(), - new SheetParallelOptions { HeaderRow = 1 }).ConfigureAwait(false); + new SheetParallelOptions { HeaderRow = 1 }); #endregion } } @@ -112,7 +106,7 @@ await SheetParallel.ForEachAsync( workbook.FirstSheet, ExcelParser.FromAttributes(), row => Interlocked.Add(ref total, row.Units), - new SheetParallelOptions { DegreeOfParallelism = 8, HeaderRow = 1 }).ConfigureAwait(false); + new SheetParallelOptions { DegreeOfParallelism = 8, HeaderRow = 1 }); #endregion } } @@ -317,14 +311,11 @@ internal static class Snippet internal static async Task Run(CancellationToken cancellationToken) { #region reading-async - var workbook = await Excel.FromXlsxFileAsync("report.xlsx", ct: cancellationToken).ConfigureAwait(false); - #region reading-async - await using (workbook.ConfigureAwait(false)) + await using var workbook = await Excel.FromXlsxFileAsync("report.xlsx", ct: cancellationToken); + + await foreach (var row in workbook.FirstSheet) { - await foreach (var row in workbook.FirstSheet.ConfigureAwait(false)) - { - Console.WriteLine(row[0].GetString()); - } + Console.WriteLine(row[0].GetString()); } #endregion } @@ -337,17 +328,14 @@ internal static class Snippet { internal static async Task Run(CancellationToken cancellationToken) { - var workbook = await Excel.FromXlsxFileAsync("report.xlsx", ct: cancellationToken).ConfigureAwait(false); #region reading-async-enumerator - await using (workbook.ConfigureAwait(false)) - { - await using var rows = workbook.FirstSheet.GetAsyncEnumerator(cancellationToken).ConfigureAwait(false); + await using var workbook = await Excel.FromXlsxFileAsync("report.xlsx", ct: cancellationToken); + await using var rows = workbook.FirstSheet.GetAsyncEnumerator(cancellationToken); - while (await rows.MoveNextAsync().ConfigureAwait(false)) - { - var row = rows.Current; - Console.WriteLine(row[0].GetString()); - } + while (await rows.MoveNextAsync()) + { + var row = rows.Current; + Console.WriteLine(row[0].GetString()); } #endregion } diff --git a/docs/snippets/Writing.cs b/docs/snippets/Writing.cs index 7f788e11..b2f8b115 100644 --- a/docs/snippets/Writing.cs +++ b/docs/snippets/Writing.cs @@ -10,31 +10,27 @@ internal static class Snippet internal static async Task Run() { #region writing-xlsx - var stream = File.Create("out.xlsx"); - #region writing-xlsx - await using (stream.ConfigureAwait(false)) - { - await using var workbook = XlsxWorkbookWriter.Create(stream).ConfigureAwait(false); + await using var stream = File.Create("out.xlsx"); + await using var workbook = XlsxWorkbookWriter.Create(stream); - await using (var sheet = workbook.AddSheet("Summary").ConfigureAwait(false)) + await using (var sheet = workbook.AddSheet("Summary")) + { + await using (var row = await sheet.StartRowAsync()) { - await using (var row = (await sheet.StartRowAsync()).ConfigureAwait(false)) - { - row.Write("Name"); - row.Write("Total"); - row.Write("Created"); - } - - await using (var row = (await sheet.StartRowAsync()).ConfigureAwait(false)) - { - row.Write("Q1"); - row.Write(42); - row.Write(DateTime.UtcNow); - } + row.Write("Name"); + row.Write("Total"); + row.Write("Created"); } - await workbook.EndAsync().ConfigureAwait(false); + await using (var row = await sheet.StartRowAsync()) + { + row.Write("Q1"); + row.Write(42); + row.Write(DateTime.UtcNow); + } } + + await workbook.EndAsync(); #endregion } } @@ -47,11 +43,7 @@ internal static class Snippet internal static async Task Run(Stream stream) { #region writing-xlsx-shared-strings - var workbook = XlsxWorkbookWriter.Create(stream, options: new XlsxWriterOptions { UseSharedStrings = true }); - #region writing-xlsx-shared-strings - await using (workbook.ConfigureAwait(false)) - { - } + await using var workbook = XlsxWorkbookWriter.Create(stream, options: new XlsxWriterOptions { UseSharedStrings = true }); #endregion } } @@ -68,13 +60,9 @@ internal static class Snippet internal static async Task Run(XlsxWorkbookWriter workbook) { #region writing-hidden-sheets - var data = workbook.AddSheet("Data"); - #region writing-hidden-sheets - await using (data.ConfigureAwait(false)) { /* rows */ } // visible - var lookups = workbook.AddSheet("Lookups", ExcelSheetVisibility.Hidden); - await using (lookups.ConfigureAwait(false)) { /* rows */ } - var audit = workbook.AddSheet("Audit", ExcelSheetVisibility.VeryHidden); - await using (audit.ConfigureAwait(false)) { /* rows */ } // not in Excel's unhide dialog + await using (var data = workbook.AddSheet("Data")) { /* rows */ } // visible + await using (var lookups = workbook.AddSheet("Lookups", ExcelSheetVisibility.Hidden)) { /* rows */ } + await using (var audit = workbook.AddSheet("Audit", ExcelSheetVisibility.VeryHidden)) { /* rows */ } // not in Excel's unhide dialog #endregion } } @@ -92,33 +80,27 @@ internal static class Snippet internal static async Task Run(Stream stream) { #region writing-styles - var workbook = XlsxWorkbookWriter.Create(stream); - #region writing-styles - await using (workbook.ConfigureAwait(false)) - { - int currency = workbook.AddStyle(new CellStyle { NumberFormat = "R$ #,##0.00" }); - int header = workbook.AddStyle(new CellStyle { Bold = true }); + await using var workbook = XlsxWorkbookWriter.Create(stream); - await using var sheet = workbook.AddSheet("Summary").ConfigureAwait(false); - sheet.SetColumnStyle(columnIndex: 1, currency); // before the first row - sheet.SetColumnWidth(columnIndex: 0, width: 20); + int currency = workbook.AddStyle(new CellStyle { NumberFormat = "R$ #,##0.00" }); + int header = workbook.AddStyle(new CellStyle { Bold = true }); - await using (var row = (await sheet.StartRowAsync(header).ConfigureAwait(false)).ConfigureAwait(false)) - { - row.Write("Product"); - row.Write("Total"); - } - { - var row = await sheet.StartRowAsync().ConfigureAwait(false); - await using (row.ConfigureAwait(false)) - { - row.Write("Widget"); - row.Write(1234.5); - } - } + await using var sheet = workbook.AddSheet("Summary"); + sheet.SetColumnStyle(columnIndex: 1, currency); // before the first row + sheet.SetColumnWidth(columnIndex: 0, width: 20); - await workbook.EndAsync().ConfigureAwait(false); + await using (var row = await sheet.StartRowAsync(header)) + { + row.Write("Product"); + row.Write("Total"); } + await using (var row = await sheet.StartRowAsync()) + { + row.Write("Widget"); + row.Write(1234.5); + } + + await workbook.EndAsync(); #endregion } } @@ -136,24 +118,20 @@ internal static class Snippet internal static async Task Run() { #region writing-xlsb - var stream = File.Create("out.xlsb"); - #region writing-xlsb - await using (stream.ConfigureAwait(false)) - { - await using var workbook = XlsbWorkbookWriter.Create(stream).ConfigureAwait(false); + await using var stream = File.Create("out.xlsb"); + await using var workbook = XlsbWorkbookWriter.Create(stream); - await using (XlsbSheetWriter sheet = workbook.AddSheet("Summary").ConfigureAwait(false).ConfigureAwait(false)) + await using (XlsbSheetWriter sheet = workbook.AddSheet("Summary")) + { + await using (XlsbRowWriter row = await sheet.StartRowAsync()) { - await using (XlsbRowWriter row = (await sheet.StartRowAsync().ConfigureAwait(false)).ConfigureAwait(false)) - { - row.Write("Name"); - row.Write("Total"); - row.Write("Created"); - } + row.Write("Name"); + row.Write("Total"); + row.Write("Created"); } - - await workbook.EndAsync().ConfigureAwait(false); } + + await workbook.EndAsync(); #endregion } } @@ -171,31 +149,27 @@ internal static class Snippet internal static async Task Run() { #region writing-xls - var stream = File.Create("out.xls"); - #region writing-xls - await using (stream.ConfigureAwait(false)) - { - await using var workbook = XlsWorkbookWriter.Create(stream).ConfigureAwait(false); + await using var stream = File.Create("out.xls"); + await using var workbook = XlsWorkbookWriter.Create(stream); - using (var sheet = workbook.AddSheet("Summary")) + using (var sheet = workbook.AddSheet("Summary")) + { + using (var row = sheet.StartRow()) { - using (var row = sheet.StartRow()) - { - row.Write("Name"); - row.Write("Total"); - row.Write("Created"); - } - - using (var row = sheet.StartRow()) - { - row.Write("Q1"); - row.Write(42); - row.Write(DateTime.UtcNow); - } + row.Write("Name"); + row.Write("Total"); + row.Write("Created"); } - await workbook.EndAsync().ConfigureAwait(false); + using (var row = sheet.StartRow()) + { + row.Write("Q1"); + row.Write(42); + row.Write(DateTime.UtcNow); + } } + + await workbook.EndAsync(); #endregion } } @@ -229,14 +203,11 @@ internal static async Task Run() new Sale { Region = "South", Units = 17, Revenue = 512.00m, Date = new DateOnly(2026, 1, 3) }, }; - var stream = File.Create("sales.xlsx"); - await using (stream.ConfigureAwait(false)) + await using var stream = File.Create("sales.xlsx"); + await using var workbook = XlsxWorkbookWriter.Create(stream); // or XlsbWorkbookWriter / XlsWorkbookWriter / CsvWorkbookWriter + await using (var sheet = workbook.AddSheet("Sales")) { - await using var workbook = XlsxWorkbookWriter.Create(stream).ConfigureAwait(false); // or XlsbWorkbookWriter / XlsWorkbookWriter / CsvWorkbookWriter - await using (var sheet = workbook.AddSheet("Sales").ConfigureAwait(false)) - { - await sheet.WriteRecordsAsync(sales, ExcelRecordLayout.FromAttributes()).ConfigureAwait(false); - } + await sheet.WriteRecordsAsync(sales, ExcelRecordLayout.FromAttributes()); } #endregion } @@ -277,7 +248,7 @@ internal static class Snippet internal static async Task Run(XlsxSheetWriter sheet, Sale[] sales) { #region writing-table-records - await sheet.WriteTableAsync(sales, "Sales", ExcelRecordLayout.FromAttributes()).ConfigureAwait(false); + await sheet.WriteTableAsync(sales, "Sales", ExcelRecordLayout.FromAttributes()); #endregion } } @@ -292,21 +263,17 @@ internal static class Snippet internal static async Task Run(Stream stream, Metric[] records) { #region writing-prefetch - var wb = XlsxWorkbookWriter.Create(stream, leaveOpen: true, options: new XlsxWriterOptions { PrefetchWrite = true }); - #region writing-prefetch - await using (wb.ConfigureAwait(false)) - { - XlsxSheetWriter sheet = wb.AddSheet("S1"); - - foreach (var record in records) - { - using XlsxRowWriter row = sheet.StartRow(); - row.Write(record.Name); - row.Write(record.Value); - } + await using var wb = XlsxWorkbookWriter.Create(stream, leaveOpen: true, options: new XlsxWriterOptions { PrefetchWrite = true }); + XlsxSheetWriter sheet = wb.AddSheet("S1"); - await sheet.EndAsync().ConfigureAwait(false); + foreach (var record in records) + { + using XlsxRowWriter row = sheet.StartRow(); + row.Write(record.Name); + row.Write(record.Value); } + + await sheet.EndAsync(); #endregion } } @@ -320,24 +287,21 @@ internal static class Snippet { internal static async Task Run(Stream stream, IEnumerable records) { - var wb = XlsxWorkbookWriter.Create(stream, leaveOpen: true); #region writing-parallel - await using (wb.ConfigureAwait(false)) - { - XlsxSheetWriter sheet = wb.AddSheet("S1"); + await using var wb = XlsxWorkbookWriter.Create(stream, leaveOpen: true); + XlsxSheetWriter sheet = wb.AddSheet("S1"); - // Header row from the layout, then one row per record. - await sheet.WriteRecordsParallelAsync(records, ExcelRecordLayout.FromAttributes()).ConfigureAwait(false); + // Header row from the layout, then one row per record. + await sheet.WriteRecordsParallelAsync(records, ExcelRecordLayout.FromAttributes()); - // Or format each row yourself; this delegate runs on several threads at once. - await sheet.WriteRecordsParallelAsync(records, static (XlsxRowWriter row, Metric record) => - { - row.Write(record.Name); - row.Write(record.Value); - }, new ParallelWriteOptions { DegreeOfParallelism = 4 }).ConfigureAwait(false); + // Or format each row yourself; this delegate runs on several threads at once. + await sheet.WriteRecordsParallelAsync(records, static (XlsxRowWriter row, Metric record) => + { + row.Write(record.Name); + row.Write(record.Value); + }, new ParallelWriteOptions { DegreeOfParallelism = 4 }); - await sheet.EndAsync().ConfigureAwait(false); - } + await sheet.EndAsync(); #endregion } } From d17287ee88581d277fd9be7e279a9657709987b7 Mon Sep 17 00:00:00 2001 From: GabrielMarquezMatte Date: Wed, 28 Oct 2026 13:55:24 -0300 Subject: [PATCH 19/19] refactor: improve code readability by restructuring methods in encryption and untrusted input documentation --- docs/guide/encryption.md | 5 +++-- docs/guide/untrusted-input.md | 12 ++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/guide/encryption.md b/docs/guide/encryption.md index fe4208b3..63ba6d5b 100644 --- a/docs/guide/encryption.md +++ b/docs/guide/encryption.md @@ -74,14 +74,15 @@ using ExcelReader.Core.Writer; using ExcelReader.Core.Writer.Xlsx; using var plain = new MemoryStream(); -await using (var workbook = XlsxWorkbookWriter.Create(plain, leaveOpen: true)) +var workbook = XlsxWorkbookWriter.Create(plain, leaveOpen: true); +await using (workbook.ConfigureAwait(false)) { // write sheets and rows as usual } plain.Position = 0; using var destination = File.Create("secret.xlsx"); -await Excel.EncryptPackageAsync(plain, destination, "hunter2"); +await Excel.EncryptPackageAsync(plain, destination, "hunter2").ConfigureAwait(false); ``` The package stream must be seekable (it is read twice, so the container never has to be buffered in diff --git a/docs/guide/untrusted-input.md b/docs/guide/untrusted-input.md index 5922d20d..2ddb7c1a 100644 --- a/docs/guide/untrusted-input.md +++ b/docs/guide/untrusted-input.md @@ -94,11 +94,13 @@ catch (Exception ex) when (IsRejectedFile(ex)) Console.WriteLine($"Rejected: {ex.Message}"); } -static bool IsRejectedFile(Exception ex) => - ex is InvalidDataException or EndOfStreamException or NotSupportedException +static bool IsRejectedFile(Exception ex) +{ + return ex is InvalidDataException or EndOfStreamException or NotSupportedException or ExcelEncryptionException or ExcelParseException || ex.GetType() == typeof(ArgumentException) || ex.GetType() == typeof(InvalidOperationException); +} ``` `LimitName` is the option's name (or `Columns`, `ArrayMaxLength`); `Limit` and `Actual` are in that @@ -140,8 +142,10 @@ file in a spreadsheet program, neutralize those fields yourself: ```csharp -static string Neutralize(string text) => - text.Length > 0 && "=+-@\t\r".Contains(text[0]) ? "'" + text : text; +static string Neutralize(string text) +{ + return text.Length > 0 && "=+-@\t\r".Contains(text[0]) ? "'" + text : text; +} row.Write(Neutralize(comment)); ```