Note
In the following code examples - for easier readability - exception handling
has been omitted.
public static CsvReader<TResult> OpenReadAnalyzed<TResult>(
string filePath,
CsvMapping mapping,
Func<Object, TResult> conversion,
Encoding? defaultEncoding = null,
Header header = Header.ProbablyPresent,
int analyzedLines = 5
)
Public Shared Function OpenReadAnalyzed(Of TResult) (
filePath As String,
mapping As CsvMapping,
conversion As Func(Of Object, TResult),
Optional defaultEncoding As Encoding = Nothing,
Optional header As Header = Header.ProbablyPresent,
Optional analyzedLines As Integer = 5
) As CsvReader(Of TResult)
public:
generic<typename TResult>
static CsvReader<TResult>^ OpenReadAnalyzed(
String^ filePath,
CsvMapping^ mapping,
Func<Object^, TResult>^ conversion,
Encoding^ defaultEncoding = nullptr,
Header header = Header::ProbablyPresent,
int analyzedLines = 5
)
static member OpenReadAnalyzed :
filePath : string *
mapping : CsvMapping *
conversion : Func<Object, 'TResult> *
?defaultEncoding : Encoding *
?header : Header *
?analyzedLines : int
(* Defaults:
let _defaultEncoding = defaultArg defaultEncoding null
let _header = defaultArg header Header.ProbablyPresent
let _analyzedLines = defaultArg analyzedLines 5
*)
-> CsvReader<'TResult>
A function that converts the content of mapping to an instance of TResult.
The function is called for each row in the CSV file and gets the CsvMapping as argument, filled with the current CsvRecord instance. The CsvMapping is passed to the function as dynamic argument: Inside the function the registered DynamicProperty instances can be used like regular .NET properties, but without IntelliSense ("late binding").
The method performs a statistical analysis on the CSV file. The result of the analysis is therefore always only an estimate, the accuracy of which increases with the number of lines analyzed.
The field delimiters COMMA (',', %x2C), SEMICOLON (';', %x3B), HASH ('#', %x23), TAB ('\t', %x09), and SPACE (' ', %x20) are recognized automatically.
This method also tries to determine the Encoding of the CSV file from the byte order mark (BOM). If no byte order mark can be found, defaultEncoding is used.
CSV data exchange with Excel:
using FolkerKinzel.CsvTools;
using FolkerKinzel.CsvTools.Mappings;
using System.Globalization;
using System.Text;
// A namespace alias helps to avoid name conflicts
// with the converters from System.ComponentModel
using Conv = FolkerKinzel.CsvTools.Mappings.TypeConverters;
namespace Examples;
internal sealed record Customer(string Name, decimal Sales, DateOnly RecentPurchase);
internal static class ExcelExample
{
internal static void CsvDataExchangeWithExcel(string filePath)
{
// Which field separators and formatting Excel accepts and exports depends on the
// "Regional Settings" in Excel. The default setting corresponds to the settings
// of the user's computer (and thus of CultureInfo.CurrentCulture).
// Using CultureInfo.CurrentCulture, the corresponding parameters can be determined
// automatically.
// The application is free to override the value of CurrentCulture for the current
// Thread if users do not use the default setting in Excel.
// This example shows the procedure for exporting CSV data to Excel. The procedure
// for importing is equivalent.(The console output is from a computer with the locale
// "de-DE".)
Console.WriteLine("Current culture: {0}", CultureInfo.CurrentCulture);
Customer[] customers = [ new("Susi", 4_711m, new DateOnly(2004, 3, 14)),
new("Tom", 38_527.28m, new DateOnly(2006, 12, 24)),
new("Sören", 25.8m, new DateOnly(2011, 8, 27)) ];
// Get the Excel arguments for CultureInfo.CurrentCulture:
(char delimiter,
IFormatProvider formatProvider,
Encoding ansi) = Csv.GetExcelArguments();
// Pass the formatProvider from the Excel arguments to all localizable converters.
// (The same CsvMapping can be used for writing and parsing.)
CsvMapping mapping = CsvMappingBuilder
.Create()
.AddProperty("Name", Conv::StringConverter.CreateNonNullable())
.AddProperty("Sales", new Conv::DecimalConverter(formatProvider))
.AddProperty("RecentPurchase", new Conv::DateOnlyConverter(formatProvider))
.Build();
static void FillMapping(Customer customer, dynamic mapping)
{
mapping.Name = customer.Name;
mapping.Sales = customer.Sales;
mapping.RecentPurchase = customer.RecentPurchase;
}
// Don't forget to pass the delimiter from the Excel arguments!
// (The textEncoding can be omitted when writing, but not when reading.)
customers.SaveCsv(filePath, mapping, FillMapping, delimiter, textEncoding: ansi);
Console.WriteLine();
Console.WriteLine(File.ReadAllText(filePath, ansi));
// =================================================
// Parsing CSV that comes from Excel:
static Customer InitializeCustomer(dynamic mapping) => new(mapping.Name,
mapping.Sales,
mapping.RecentPurchase);
// Using this method allows to switch automatically to Unicode if the file
// has a byte order mark, and to detect a different delimiter character if
// the user had changed the default settings in Excel.
using CsvReader<Customer> reader = CsvConverter.OpenReadAnalyzed(filePath,
mapping,
InitializeCustomer,
defaultEncoding: ansi);
Console.WriteLine();
Console.WriteLine("The customer with the lowest sales is {0}.",
reader.MinBy(x => x.Sales)?.Name);
}
}
/*
Console output:
Current culture: de-DE
Name;Sales;RecentPurchase
Susi;4711;14.03.2004
Tom;38527,28;24.12.2006
Sören;25,8;27.08.2011
The customer with the lowest sales is Sören.
*/
ArgumentNullException | filePath, or mapping, or conversion is null. |
ArgumentOutOfRangeException | header is not a defined value of the Header enum. - or - header is a combination of Header values. |
CsvFormatException | Invalid CSV file. Try to increase the value of analyzedLines to get a better analyzer result! |