All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
CsvWriternot quoting fields that contain a bare carriage return (\r)- Per RFC 4180 a field containing CR, LF, the separator, or a quote must be quoted;
CsvWriteronly triggered on\n, the separator,', and", so a value likea\rbwas written unquoted — mis-parsed by strict readers and split into two records when re-read CsvBufferWriteralready included\r; allCsvWriterpaths (sync, async, and theReadOnlyMemory<char>paths) now match it
- Per RFC 4180 a field containing CR, LF, the separator, or a quote must be quoted;
- Removed a per-row
char[]allocation inCsvWriter.WriteLine/WriteLineAsyncby caching the fixed quote-trigger characters in a static array and checking the variable separator separately
2.0.245 - 2026-05-17
- Memory-based reader paths dropping records after blank lines (#122)
ReadFromMemoryandReadAsSpanfromReadOnlyMemory<char>terminated iteration at the first blank line in the middle of the input- All five reader paths now continue parsing past blank lines uniformly
- Unescaped inner quotes in quoted fields throwing
InvalidOperationException(#114)- Fields like
"JOHN "WAYNE""(a quoted field containing unescaped inner quotes) now parse leniently with the inner quotes preserved as literal characters - Fix landed incidentally with the engine unification in #118; covered by regression tests against the originally reported
FMBC_EMPPERS.csvacross all read paths
- Fields like
- Quoted commas split as separate columns when the opening quote was preceded by whitespace under
TrimData=true(#71)A, ",,"was parsed as four columns because the splitter only entered quote mode when the"sat at the exact field start; the leading space pushed it one position paststartand the inner commas were treated as separators- With
TrimData=true, the splitter now accepts an opening quote after any run of leading whitespace, andIsUnterminatedQuotedValueapplies the same leniency so multiline continuation agrees with the splitter - Strict (non-
TrimData) behavior is preserved:"...withoutTrimDatastill parses as an unquoted field
- Unified the four
CsvReaderread loops behind a single JIT-devirtualized engine (#118)- Sync, async, span, optimized-memory, and from-memory paths now share one implementation
- Struct line sources + struct row factories with generic constraints let the JIT monomorphize and inline per call site
- HeaderAbsent + multiline-first-record fix now applies uniformly to all five paths
- Dropped the
ArrayPool<char>rent/copy/return dance fromMemorySliceLineSource.Concat(#119)- The pool was rented and immediately discarded on every multiline continuation
- Direct
string.Concat-based path is both simpler and faster
- Primed the row split cache from the engine's multiline loop (#120)
- The engine already splits to detect unterminated quoted values; the result is now reused by the row instead of being re-split lazily on first column access
- Pre-sized the split list using the known header count, avoiding
List<T>grow-and-copy on the per-row hot path - Cached
SearchValues<char>and switched tostring.Createin the writer pathsCsvBufferWriter.WriteCellandCsvWriter's Memory-variant write paths were allocating a freshSearchValues<char>on every cell becauseMemoryExtensions.IndexOfAny(ReadOnlySpan,ReadOnlySpan)builds one internally for vectorized search; now cached in a static field with the variable separator checked viaContainsCsvBufferWriter.ToStringallocated an intermediatechar[]before copying into the final string; now usesstring.Createfor a single allocation- One-shot
WriteCsv + ToStringallocations dropped from ~3.0x theStringBuilderpath to ~0.78x, constant across 100 → 100k rows
- Updated dependencies:
- microsoft.net.test.sdk to 18.5.1 (#117)
- mstest monorepo to 4.2.3 (#116)
2.0.217 - 2026-01-04
- AutoRenameHeaders option to handle duplicate and empty headers (#95)
- WriteAsync support for IEnumerable<string[]> (#104)
- Correct escaped quote detection logic in IsUnterminatedQuotedValue (#110)
- The modulo check for determining if a quoted field is unterminated was inverted
- Fields ending with escaped quotes (e.g.,
"test"""for valuetest") were incorrectly detected as unterminated - This caused rows to merge together when
AllowNewLineInEnclosedFieldValueswas enabled
- Resolve build warnings and test failures
- Pre-allocate list capacity in SplitLine (#113)
- Updated dependencies:
- actions/checkout to v6 (#108)
- microsoft.net.test.sdk to 18.0.1
- mstest monorepo to 4.0.2
2.0.205 - 2025-10-21
- Support for nullable headers and convenience overloads (#66)
- Span/Memory APIs for .NET 8.0+ for high-performance scenarios
- .NET 9 support in tests (#92)
- .NET 9 setup for CodeQL workflow (#91)
- Correct header count for HeaderAbsent mode with multiline fields (#72)
- Compile error in Assert.Throws
- Relaxed performance test thresholds for CI environments
- Moved PRD to docs folder and updated documentation guidelines
- Enhanced documentation with architecture details and NuGet badges
- Updated dependencies:
- mstest monorepo to v4
- microsoft.net.test.sdk to v18
- github/codeql-action to v4
- actions/stale to v10
- actions/setup-dotnet to v5
- actions/checkout to v5
- microsoft.net.test.sdk to 17.14.1
- mstest monorepo to 3.9.3
- Eliminated regex usage in CSV parsing for better performance
2.0.170 - 2025-05-20
- AllowEnclosedFieldValues option (#51, #84)
- LineHasColumn method to check if a column exists (#32, #90)
- WriteAsync overload with CancellationToken support (#76)
- Comprehensive test coverage for:
- Comma inside quoted text (#73, #86)
- Invalid CSV scenarios (#87)
- Async operations (#88)
- Skip-header functionality (#88)
- Writer null cell handling (#74, #83)
- Environment.NewLine usage in writer tests (#89)
- Removed regex splitting in favor of more efficient parsing (#82)
- Expanded README with async and helper APIs documentation (#85)
- Updated target frameworks and NuGet properties
- Updated tests to .NET 9
- Updated dependencies:
- mstest monorepo to 3.9.0
- microsoft.net.test.sdk to 17.14.0
- github/codeql-action to v3
- mstest monorepo to 3.8.3
2.0.128 - 2025-02-20
- .NET 8.0 target framework support
- Trimming and AOT (Ahead-of-Time compilation) support
- Collection expressions support
- Additional .NET 8 method overloads
- Deprecated .NET Standard 1.0 target (no longer recommended)
- Fixed NuSpec paths
- Code cleanup: warnings and whitespace
- ReSharper code style improvements
- Updated dependencies:
- actions/checkout to v4
- actions/stale to v9
- microsoft.net.test.sdk to v17.6.0 (#61)
- microsoft.net.test.sdk to v17.5.0 (#58)
- actions/stale to v7 (#59)
2.0.93 - 2022-12-10
- Updated microsoft.net.test.sdk to v17.4.0 (#55)
- Updated microsoft.net.test.sdk to v17.3.2 (#53)
- Updated actions/stale to v6 (#54)
2.0.87 - 2022-09-02
- Async methods for Write and WriteToText (#52)
- Support for IAsyncEnumerable<string[]>
- Various fixes for async write operations (#52)
- Updated mstest monorepo to v2.2.10 (#40)
2.0.84 - 2022-05-04
- GetColumn and GetBlock extension methods (#46)
- GetColumn(int columnNo) and GetColumn(int columnNo, Func<string, T>)
- GetBlock(int row_start, int row_length, int col_start, int col_length)
- Updated github/codeql-action to v2 (#45)
2.0.80 - 2022-04-21
- Updated microsoft.net.test.sdk to v17 (#43)
- Updated multiple dependencies:
- microsoft.net.test.sdk to v15.9.2 (#37)
- microsoft.sourcelink.github to v1.1.1 (#38)
- actions/checkout to v3 (#41)
- actions/stale to v5 (#42)
2.0.76 - 2022-04-21
- Updated mstest monorepo to v2 (#44)
2.0.67 - 2022-03-31
- Renovate configuration for automated dependency updates (#36)
2.0.65 - 2022-01-18
- Fixed issue #35 with proper test coverage
2.0.64 - 2021-12-26
- Option to skip header when writing CSV files
2.0.62 - 2020-12-24
- Moved custom logic from SplitLine to CsvLineSplitter
- Improved performance for .Replace call
2.0.61 - 2020-12-23
- Span/Memory support for .NET Core 3.1 and .NET Standard 2.1
- .NET Core 3.1 support
- .NET Standard 2.1 target (enables use in Blazor WASM projects) (#29)
- CodeQL analysis workflow
- Fixed issue #28
- Prefer Span/Memory APIs for better performance on supported frameworks
The library was initially released with comprehensive CSV reading and writing functionality:
- CSV reading from TextReader, Stream, and string
- CSV writing with header support
- Configurable separators with auto-detection
- Header row handling (present/absent modes)
- Quote and escape character handling
- Multiline field support (#24)
- Column access by name or index
- Custom row validation and skipping
- RowsToSkip and SkipRow for filtering
- TrimData for whitespace handling
- Comparer for case-insensitive column names
- ValidateColumnCount for strict validation
- ReturnEmptyForMissingColumn for flexible access
- Aliases for alternative column names
- AllowNewLineInEnclosedFieldValues for multiline fields
- AllowBackSlashToEscapeQuote for escape sequences
- AllowSingleQuoteToEncloseFieldValues for single-quote support
- SourceLink support (2018-08-28)
- CsvWriter class for generating CSV output (2018-02-14)
- Values property to retrieve all row values (#16)
- codecov integration (2019-02-17)
- CodeQL analysis (2020-10-02)
- Fixed issues #10, #11, #14, #19, #28, #35
- Fixed multiline parsing bugs (#24)
- Fixed unterminated quoted value detection
- Initial targets: .NET Standard 1.3, .NET 4.0
- Added .NET Standard 2.0 support
- Added .NET Standard 2.1 support (2020)
- Added .NET Core 3.1 support (2020)
For more details on each release, see the commit history or visit the NuGet package page.