Table of Contents

Addax - Overview

Introduction

A general-purpose framework that works with tabular data represented as delimiter-separated values, the main types are:

  • The low-level API flavor:
    • The TabularReader type provides forward-only, read-only access to tabular data fields as strings or typed values.
    • The TabularWriter type provides forward-only, write-only access to tabular data fields as strings or typed values.
  • The high-level API flavor:
    • The TabularReader<T> type provides forward-only, read-only access to tabular data records as typed plain objects.
    • The TabularWriter<T> type provides forward-only, write-only access to tabular data records as typed plain objects.
  • The minimal API flavor:
    • The TabularData type provides static methods for working with collections of tabular data records and inferring dialects.

The value converter abstraction provides an ability to work with tabular data fields as typed values, while the record handler abstraction provides an ability to work with tabular data records as typed plain objects by defining a complete read-write workflow. Although record handlers can be created manually, by default they are generated by the built-in source generator according to the metadata explicitly declared with attributes. Each API flavor requires an instance of the TabularDialect type that specifies how to read and write tabular data. Framework types that perform I/O operations provide synchronous and asynchronous API, including cancellation support.

How to Use

How to work with tabular data of a specific structure:

var dialect = new TabularDialect("\r\n", ',', '\"');

using (var writer = new TabularWriter<Book>(File.Create("books.csv"), dialect))
{
    var book1 = new Book
    {
        Author = "Lewis Carroll",
        Title = "Alice's Adventures in Wonderland",
        Published = new(1865, 11, 09)
    };

    writer.WriteRecord(book1);

    var book2 = new Book
    {
        Author = "H. G. Wells",
        Title = "The Time Machine",
        Published = new(1894, 03, 17)
    };

    writer.WriteRecord(book2);
}

using (var reader = new TabularReader<Book>(File.OpenRead("books.csv"), dialect))
{
    while (reader.TryReadRecord())
    {
        var book = reader.CurrentRecord;

        Console.WriteLine($"{book.Author} '{book.Title}' ({book.Published})");
    }
}

[TabularRecord]
internal struct Book
{
    [TabularFieldOrder(0)]
    public string? Author;

    [TabularFieldOrder(1)]
    public string? Title;

    [TabularFieldOrder(2)]
    public DateOnly? Published;
}

How to work with tabular data of a specific structure that has a header:

var dialect = new TabularDialect("\r\n", ',', '\"');

using (var writer = new TabularWriter<Book>(File.Create("books.csv"), dialect))
{
    var book1 = new Book
    {
        Author = "Lewis Carroll",
        Title = "Alice's Adventures in Wonderland",
        Published = new(1865, 11, 09)
    };

    writer.WriteRecord(book1);

    var book2 = new Book
    {
        Author = "H. G. Wells",
        Title = "The Time Machine",
        Published = new(1894, 03, 17)
    };

    writer.WriteRecord(book2);
}

using (var reader = new TabularReader<Book>(File.OpenRead("books.csv"), dialect))
{
    while (reader.TryReadRecord())
    {
        var book = reader.CurrentRecord;

        Console.WriteLine($"{book.Author} '{book.Title}' ({book.Published})");
    }
}

[TabularRecord]
internal struct Book
{
    [TabularFieldName("author")]
    [TabularFieldOrder(0)]
    public string? Author;

    [TabularFieldName("title")]
    [TabularFieldOrder(1)]
    public string? Title;

    [TabularFieldName("published")]
    [TabularFieldOrder(2)]
    public DateOnly? Published;
}

How to work with tabular data of a specific structure using the minimal API:

var dialect = new TabularDialect("\r\n", ',', '\"');

var books = new Book[]
{
    new()
    {
        Author = "Lewis Carroll",
        Title = "Alice's Adventures in Wonderland",
        Published = new(1865, 11, 09)
    },
    new()
    {
        Author = "H. G. Wells",
        Title = "The Time Machine",
        Published = new(1894, 03, 17)
    }
};

TabularData.WriteRecords(File.Create("books.csv"), dialect, books);

books = TabularData.ReadRecords<Book>(File.OpenRead("books.csv"), dialect);

foreach (var book in books)
{
    Console.WriteLine($"{book.Author} '{book.Title}' ({book.Published})");
}

[TabularRecord]
internal struct Book
{
    [TabularFieldOrder(0)]
    public string? Author;

    [TabularFieldOrder(1)]
    public string? Title;

    [TabularFieldOrder(2)]
    public DateOnly? Published;
}