Lyo.Csv
1.0.1
dotnet add package Lyo.Csv --version 1.0.1
NuGet\Install-Package Lyo.Csv -Version 1.0.1
<PackageReference Include="Lyo.Csv" Version="1.0.1" />
<PackageVersion Include="Lyo.Csv" Version="1.0.1" />
<PackageReference Include="Lyo.Csv" />
paket add Lyo.Csv --version 1.0.1
#r "nuget: Lyo.Csv, 1.0.1"
#:package Lyo.Csv@1.0.1
#addin nuget:?package=Lyo.Csv&version=1.0.1
#tool nuget:?package=Lyo.Csv&version=1.0.1
Lyo.Csv
Owned implementation of Lyo.Csv.Models. CsvService composes a CsvWriter and CsvReader over an internal field tokenizer/writer and cached type binder. Multi-targets net10.0;netstandard2.0; async, streaming, and option-based overloads are only available on net10.0.
Features
- Strongly-typed read/write via
IEnumerable<T>/List<T>andIAsyncEnumerable<T>(net10). - Row/column dictionary (
IReadOnlyDictionary<int, IReadOnlyDictionary<int, string>>) read and write. Lyo.DataTable.Models.DataTableround-trip includingFooter(ParseFileAsDataTablewithhasFooterRow,ExportToCsvFromDataTablealways appends footer when present, plus an HTML helperExportToHtmlTable).- CSV → DataTable pooling via
CsvOptions.Pooling/CsvParseOptions.Pooling(defaultsPoolValues=false; estimate iscols × (rows+1)after the full CSV is buffered). - Selected-property export (
IReadOnlyList<PropertyInfo>), custom-header export (IReadOnlyDictionary<string, PropertyInfo>), and formatter export (IReadOnlyDictionary<string, Func<T, string>>). - URL download helpers (
ParseFromUrl*) that share an optional injectedHttpClient. - Append, combine, and split file operations (async,
net10.0only). - Streaming reads (
IAsyncEnumerable<T>and string-row streams),IAsyncEnumerableexports, chunked processing, statistics, schema validation, column-mapping parses, and CSV-to-CSV comparison. - Dialect via
CsvOptions: delimiter, quote, escape, comments, trim, blank-line skip, column-count detection, culture, encoding. - Header rename via
[CsvColumn]; encoding viaSetEncoding/SetOptions;CodePagesEncodingProviderregistered in the service constructor. - Bundled
ICsvValueConverterimplementations:DecimalCsvConverter,Int32CsvConverter,Int64CsvConverter,YesNoBoolCsvConverter. CsvErrorCodesconstants (CSV_EXPORT_FAILED,CSV_PARSE_FAILED,CSV_OPERATION_CANCELLED,CSV_FILE_OPERATION_FAILED,CSV_VALIDATION_FAILED) used when wrapping failures inResult<T>.
Examples
Register with DI
using Lyo.Csv;
using Lyo.Csv.Models;
services.AddCsvService();
services.AddCsvService(o => {
o.Pooling.PoolValues = true; // opt in for high-duplication grids
o.Pooling.PoolingCellThreshold = 512;
o.Delimiter = ";";
o.HasHeaderRecord = true;
o.AllowComments = true;
});
services.AddCsvService(new CsvOptions { Delimiter = "|", Quote = '"', Escape = '"' });
services.AddCsvService((provider, options) => {
var feature = provider.GetRequiredService<IFeatureFlags>();
options.Delimiter = feature.UseSemicolons ? ";" : ",";
});
Quick start
public sealed class ReportingService(ICsvService csv)
{
public async Task ExportAsync(IEnumerable<Person> rows, Stream output, CancellationToken ct)
=> await csv.ExportToCsvStreamAsync(rows, output, ct);
public async Task<List<Person>> ImportAsync(string path, CancellationToken ct)
=> await csv.ParseFileAsync<Person>(path, ct);
}
public sealed record Person(int Id, string Name, int Age);
Options and column attributes
csv.SetEncoding(new UTF8Encoding(encoderShouldEmitUTF8Identifier: true));
csv.SetOptions(new CsvOptions {
Delimiter = ";",
TrimFields = true,
IgnoreBlankLines = true,
AllowComments = true,
Comment = '#',
});
public sealed class Person
{
[CsvColumn(Ignore = true)]
public int Id { get; set; }
[CsvColumn("Full Name")]
public string Name { get; set; }
[CsvColumn("Years Old")]
public int Age { get; set; }
}
Column shaping
IReadOnlyList<PropertyInfo> selected = [
typeof(Person).GetProperty(nameof(Person.Name))!,
typeof(Person).GetProperty(nameof(Person.Age))!,
];
csv.ExportToCsv(rows, selected, "out.csv");
IReadOnlyDictionary<string, PropertyInfo> namedColumns = new Dictionary<string, PropertyInfo> {
["Full Name"] = typeof(Person).GetProperty(nameof(Person.Name))!,
["Years"] = typeof(Person).GetProperty(nameof(Person.Age))!,
};
await csv.ExportToCsvStreamAsync(rows, namedColumns, stream, ct);
IReadOnlyDictionary<string, Func<Person, string>> formatters = new Dictionary<string, Func<Person, string>> {
["Display"] = p => $"{p.Name} ({p.Age})",
["Id"] = p => p.Id.ToString("D6"),
};
await csv.ExportToCsvStreamAsync(rows, formatters, stream, ct);
DataTable, dictionary, and HTML helpers
Result<DataTable> parsed = csv.ParseFileAsDataTable("in.csv", hasHeaderRow: true, hasFooterRow: true);
csv.ExportToCsvFromDataTable(parsed.ValueOrThrow(), "out.csv"); // writes Footer as trailing row when present
var grid = csv.ParseFileAsDictionary("in.csv");
csv.ExportToCsvFromDictionary(grid, "out.csv", hasHeaderRow: true, hasFooterRow: true);
string html = csv.ExportToHtmlTable(File.ReadAllBytes("in.csv"), hasHeaderRow: true, hasFooterRow: true);
Streaming, options, statistics, validation, comparison
await foreach (var row in csv.ParseFileStreamingAsync<Person>("big.csv", new CsvParseOptions {
ContinueOnError = true,
OnError = err => log.LogWarning("Row {Row}: {Message}", err.RowNumber, err.Message),
RowFilter = cells => cells["Status"] == "active",
MaxRows = 100_000,
}, ct)) {
// process row
}
await foreach (var cells in csv.ParseFileRowsStreamingAsync("big.csv", ct)) {
// untyped string cells
}
await csv.ExportToCsvStreamAsync(asyncRows, stream, ct);
CsvStatistics stats = await csv.GetStatisticsAsync("big.csv", ct);
await csv.ProcessFileInChunksAsync<Person>(
"big.csv",
chunkSize: 1_000,
processChunk: async batch => await sink.WriteAsync(batch),
ct: ct);
ValidationResult validation = await csv.ValidateAsync("in.csv", new CsvSchema {
RequireAllColumns = true,
AllowExtraColumns = false,
Columns = [
new CsvColumn { Name = "Id", IsRequired = true },
new CsvColumn { Name = "Name", IsRequired = true },
],
}, ct);
CsvComparisonResult diff = await csv.CompareFilesAsync("v1.csv", "v2.csv", keyColumn: "Id", ct);
Append / combine / split (net10.0)
await csv.AppendToCsvAsync(rows, "log.csv", includeHeaderIfMissing: true, ct);
await csv.CombineCsvFilesAsync(parts, "merged.csv", includeHeaders: true, ct);
await csv.SplitCsvFileAsync("merged.csv", rowsPerFile: 10_000, outputDirectory: "chunks", ct);
Benchmarks
UTF-8 export of 100,000 sample rows in tens of milliseconds.
- Portfolio suite:
csv - CSV UTF-8 export
Dependency injection
AddCsvService registers a singleton CsvService and routes ICsvService, ICsvWriter, and ICsvReader to the same instance. Overloads accept Action<CsvOptions>, an options instance, Action<IServiceProvider, CsvOptions>, and AddCsvServiceFromConfiguration (binds Csv and optional DataTablePooling sections). Default CSV pooling remains off.
Output targets
Each export path is available as file / stream / TextWriter / string / byte array
overloads, in sync (all TFMs) and async (net10.0) flavors:
csv.ExportToCsv(rows, "out.csv");
csv.ExportToCsvStream(rows, stream);
csv.ExportToCsv(rows, textWriter);
string text = csv.ExportToCsvString(rows);
byte[] bytes = csv.ExportToCsvBytes(rows);
await csv.ExportToCsvAsync(rows, "out.csv", ct);
await csv.ExportToCsvStreamAsync(rows, stream, ct);
string textAsync = await csv.ExportToCsvStringAsync(rows, ct);
byte[] bytesAsync = await csv.ExportToCsvBytesAsync(rows, ct);
URL and batch
Result<DataTable> table = await csv.ParseFromUrlAsDataTableAsync(url, hasHeaderRow: true, hasFooterRow: true, ct);
List<Person> rows = await csv.ParseFromUrlAsync<Person>(url, ct);
IReadOnlyList<Result<DataTable>> results =
await csv.BatchParseFilesAsDataTableAsync(paths, hasHeaderRow: true, hasFooterRow: true, ct);
If you do not supply an HttpClient to the constructor, a fresh one is created per URL
call and disposed afterward; production callers should inject one via DI.
Pass hasFooterRow: true when the last physical row should become DataTable.Footer (default false).
Dialect defaults
Default CsvOptions use comma delimiter, RFC doubled quotes, header row on, blank-line skip, field trim, and DetectColumnCountChanges (throws CsvBadDataException on uneven rows). Header names match properties case-insensitively after trim; rename with [CsvColumn]. Prefer typed/IAsyncEnumerable streams for large files — Parse*AsDataTable* materializes the full grid.
Public API (generated)
CsvErrorCodesCsvServiceDecimalCsvConverterExtensionsInt32CsvConverterInt64CsvConverterIsExternalInitYesNoBoolCsvConverter
License
Copyright © Lyo
Dependencies
Generated from ProjectReference / PackageReference (same model as docs/Lyo.ProjectGraph.html).
Lyo.Common— (direct, lyo)Lyo.Csv.Models— (direct, lyo)Lyo.Exceptions— (direct, lyo)Lyo.Result— (direct, lyo)Microsoft.Extensions.Configuration10.0.5— (direct, microsoft)Microsoft.Extensions.Configuration.Binder10.0.5— (direct, microsoft)Microsoft.Extensions.DependencyInjection.Abstractions10.0.5— (direct, microsoft)Microsoft.Extensions.Logging.Abstractions10.0.5— (direct, microsoft)Microsoft.Extensions.Options10.0.5— (direct, microsoft)System.Text.Encoding.CodePages10.0.5— (direct, microsoft)Lyo.DataTable.Models— (transitive, lyo)System.Memory4.6.3— (transitive, microsoft, netstandard2.0)System.Text.Json10.0.5— (transitive, microsoft, netstandard2.0)
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Lyo.Common (>= 1.0.1)
- Lyo.Csv.Models (>= 1.0.1)
- Lyo.Exceptions (>= 1.0.1)
- Lyo.Result (>= 1.0.1)
- Microsoft.Extensions.Configuration (>= 10.0.5)
- Microsoft.Extensions.Configuration.Binder (>= 10.0.5)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Options (>= 10.0.5)
- System.Text.Encoding.CodePages (>= 10.0.5)
-
net10.0
- Lyo.Common (>= 1.0.1)
- Lyo.Csv.Models (>= 1.0.1)
- Lyo.Exceptions (>= 1.0.1)
- Lyo.Result (>= 1.0.1)
- Microsoft.Extensions.Configuration (>= 10.0.5)
- Microsoft.Extensions.Configuration.Binder (>= 10.0.5)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
- Microsoft.Extensions.Options (>= 10.0.5)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Lyo.Csv:
| Package | Downloads |
|---|---|
|
Lyo.Reporting.Postgres
PostgreSQL reporting data layer with EF Core, optional auto-migrations, and report generation orchestration. |
|
|
Lyo.Api.Export.Csv
CSV export format handler for Lyo.Api export service. |
GitHub repositories
This package is not used by any popular GitHub repositories.