FixedWidthParser.NET
1.0.0-preview1
See the version list below for details.
dotnet add package FixedWidthParser.NET --version 1.0.0-preview1
NuGet\Install-Package FixedWidthParser.NET -Version 1.0.0-preview1
<PackageReference Include="FixedWidthParser.NET" Version="1.0.0-preview1" />
<PackageVersion Include="FixedWidthParser.NET" Version="1.0.0-preview1" />
<PackageReference Include="FixedWidthParser.NET" />
paket add FixedWidthParser.NET --version 1.0.0-preview1
#r "nuget: FixedWidthParser.NET, 1.0.0-preview1"
#:package FixedWidthParser.NET@1.0.0-preview1
#addin nuget:?package=FixedWidthParser.NET&version=1.0.0-preview1&prerelease
#tool nuget:?package=FixedWidthParser.NET&version=1.0.0-preview1&prerelease
FixedWidthParser
A high-performance, low-allocation library for parsing and writing fixed-width (flat) files in .NET 10. Columns are declared with attributes; accessors are compiled once per type via expression trees, so the hot path is allocation-free per line (only the string columns allocate, and even those can be interned with a StringPool).
Features
- Attribute-driven column mapping (
[FixedColumn(start, length)]) on properties and public fields. - Parsing: single line, plus lazy batch reading from a
TextReader,Streamor file — synchronous (IEnumerable<T>with a struct enumerator) and asynchronous (IAsyncEnumerable<T>), without allocating a string per line. - Writing: single record and batches, synchronous and asynchronous, with
StreamWriterreuse andReadOnlySpan<T>overloads for zero-allocation output. - Configurable formatting per column: alignment, padding character, format string, and an explicit overflow policy (no silent data loss).
- Culture-aware for numeric and
ISpanParsable/ISpanFormattabletypes (includingdouble/floatvia csFastFloat). - Layout validation at construction: rejects negative
Start, non-positiveLengthand overlapping columns with a clear error. ref structmodel support on the parser (verified on .NET 10).
Requirements
- .NET 10 (
net10.0)
Dependencies: CommunityToolkit.HighPerformance (StringPool) and csFastFloat (fast double/float parsing).
Installation
dotnet add package FixedWidthParser.NET
Or as a <PackageReference>:
<PackageReference Include="FixedWidthParser.NET" Version="1.0.0" />
The package ships the Roslyn source generator bundled as an analyzer, so models that implement
IFixedWidthModel<TSelf> get a reflection-free TryParse generated automatically — no extra
package or setup required.
Defining a model
using FixedWidthParser.Attributes;
public readonly record struct Person
{
public Person()
{
Name = string.Empty;
Age = 0;
Salary = 0.0;
}
[FixedColumn(0, 10)] public string Name { get; init; }
[FixedColumn(10, 5)] public int Age { get; init; }
[FixedColumn(15, 10)] public double Salary { get; init; }
}
A model only needs a parameterless constructor. start is the 0-based offset and length the column width.
Parsing
A single line
using System.Globalization;
using FixedWidthParser.Parsers;
var parser = new FixedWidthParser<Person>();
if (parser.TryParse("John Doe 30 60000.00 ", CultureInfo.InvariantCulture, stringPool: null, out var person))
{
// person.Name == "John Doe", person.Age == 30, person.Salary == 60000.0
}
Many lines / files (synchronous)
using FixedWidthParser.Readers;
var reader = new FixedWidthReader<Person>(CultureInfo.InvariantCulture);
foreach (var person in reader.ReadFile("people.txt"))
{
// ...
}
Read(TextReader) and Read(Stream, encoding, leaveOpen) are also available. Reading is lazy and reuses a single pooled buffer; lines are sliced directly from the buffer, so no string is allocated per line. A malformed line throws a FormatException carrying the line number.
Many lines / files (asynchronous)
await foreach (var person in reader.ReadFileAsync("people.txt"))
{
// ...
}
ReadAsync(TextReader) and ReadAsync(Stream, encoding, leaveOpen) mirror the synchronous overloads; ReadFileAsync uses true async file I/O. Cancellation is honored via WithCancellation.
Writing
using FixedWidthParser.Writers;
var writer = new FixedWidthWriter<Person>();
var people = new[]
{
new Person { Name = "John Doe", Age = 30, Salary = 60000 },
new Person { Name = "Jane", Age = 28, Salary = 55000 },
};
using var stream = File.Create("out.txt");
writer.WriteMany(stream, people.AsSpan(), CultureInfo.InvariantCulture);
Overloads cover Stream/StreamWriter × IEnumerable<T>/ReadOnlySpan<T>, plus WriteAsync/WriteManyAsync. Reusing a StreamWriter (or passing a span) keeps writing allocation-free per line.
Formatting options
Each column can be tuned through named attribute arguments:
[FixedColumn(0, 8, Alignment = Alignment.Right, Padding = '0')] public int Id { get; init; } // "00000042"
[FixedColumn(8, 10, Format = "F2")] public double Amount { get; init; } // "1234.50 "
[FixedColumn(18, 5, Overflow = OverflowBehavior.Truncate)] public string Code { get; init; }
Alignment—Left(default) orRight.Padding— fill character (default space; e.g.'0'for zero-padding).Format— format string passed toISpanFormattable(e.g."F2","N0"); ignored forstring.Overflow—Default,TruncateorThrow.Defaultresolves per type: strings truncate, numeric types throw — so an out-of-range number is never written blank silently.
Culture handling
Pass an IFormatProvider to TryParse, the reader constructor, or the write methods. The generic path (ISpanParsable/ISpanFormattable, e.g. decimal) and the double/float processors all honor it (the decimal separator is derived from the culture). When the provider is null, '.' is used.
StringPool (interning)
Pass a CommunityToolkit.HighPerformance.Buffers.StringPool to intern repeated string-column values, driving allocations toward zero:
var pool = new StringPool();
var reader = new FixedWidthReader<Person>(CultureInfo.InvariantCulture, stringPool: pool);
This is a deliberate time vs. memory trade-off: pooling removes per-line string allocations but costs extra CPU (hashing + lookup). Prefer it for GC-sensitive / high-concurrency workloads; skip it for raw throughput.
Validation
Invalid layouts fail fast at construction (new FixedWidthParser<T>() / new FixedWidthWriter<T>()) with an InvalidOperationException: negative Start, Length < 1, or overlapping columns. Adjacent columns (end of one == start of the next) are valid.
Performance
Measured with BenchmarkDotNet (MemoryDiagnoser) on .NET 10. Highlights:
- Parsing a line is ~30 ns and allocates only the string column (~40–48 B); with a
StringPoolit is zero-alloc. - Reading span-based vs. a naive
ReadLine()+ parse: faster and ~3× less memory; with a pool, allocations are a small constant regardless of line count. - Writing with
StreamWriterreuse (or aReadOnlySpan<T>) is zero-alloc per line.
Run them yourself:
dotnet run -c Release --project tests/Benchmarks/Benchmarks.csproj -- --filter "*ReaderBenchmarks*"
Reports (including full JSON for cross-commit comparison) are written to tests/Benchmarks/BenchmarkDotNet.Artifacts/results.
ref struct models
The parser accepts ref struct models (where TModel : new(), allows ref struct), useful for stack-only, zero-heap row processing:
public ref struct Row
{
public Row() { Name = string.Empty; Age = 0; }
[FixedColumn(0, 10)] public string Name { get; set; }
[FixedColumn(10, 5)] public int Age { get; set; }
}
var parser = new FixedWidthParser<Row>();
parser.TryParse(line, CultureInfo.InvariantCulture, null, out var row);
(The batch readers and the writer use a regular where TModel : new() constraint, since IEnumerable<T> cannot carry a ref struct.)
Project layout
src/FixedWidthParser/ The library
tests/FixedWidthParser.Tests/ xUnit test suite
tests/Benchmarks/ BenchmarkDotNet benchmarks
Building and testing
dotnet build Benchmarks.slnx -c Release
dotnet test tests/FixedWidthParser.Tests/FixedWidthParser.Tests.csproj
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- CommunityToolkit.HighPerformance (>= 8.4.2)
- csFastFloat (>= 4.1.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.1.1 | 136 | 7/15/2026 |
| 1.1.0 | 125 | 6/15/2026 |
| 1.0.0 | 119 | 6/11/2026 |
| 1.0.0-preview1 | 111 | 6/9/2026 |