Row read layer

The row read layer exposes parquet data as strongly typed rows. It is built on top of the logical reader.

Use it when you want to ingest data as rows instead of columns.

The examples use the EventSchema type declared in Schema. The same declaration is also used by the logical read layer and the writing APIs.

Read rows

Call CreateRowReader and enumerate the reader:

using var stream = File.OpenRead(path);
using EventSchema.RowReader reader = EventSchema.CreateRowReader(stream);

foreach (EventSchema.ReadRow row in reader)
{
    string? name = row.Name.IsNull ? null : Encoding.UTF8.GetString(row.Name.Value);
    Console.WriteLine($"{row.Id}: {name ?? "<null>"} at {row.OccurredAt:O}");
}

The reader binds properties to file columns by name, so the columns do not need to appear in the same order in the file.

You can also use MoveNext and Current when explicit iteration is more convenient:

while (reader.MoveNext())
{
    EventSchema.ReadRow row = reader.Current;
    Console.WriteLine(row.Id);
}
Note

A row is a temporary view over the reader's current buffers. Read its properties before advancing the reader. Binary properties return a scoped value whose bytes must be consumed before the reader advances.

Binary values expose their bytes through Value and their null state through IsNull. Read the span directly to avoid allocating a string.

When the bytes must outlive the current iteration, copy the span into caller-owned storage before advancing the reader.

Read selected properties

Pass a projection to decode only the properties you need:

EventSchema.Projection projection = EventSchema.Projection.Id |
    EventSchema.Projection.Name;

using var stream = File.OpenRead(path);
using EventSchema.RowReader reader = EventSchema.CreateRowReader(stream, projection);

foreach (EventSchema.ReadRow row in reader)
{
    string? name = row.Name.IsNull ? null : Encoding.UTF8.GetString(row.Name.Value);
    Console.WriteLine($"{row.Id}: {name ?? "<null>"}");
}

Every property has a matching projection. Combine projections with |, or use Projection.All to select every property. Accessing a property that was not selected throws InvalidOperationException.

Schema compatibility

By default, the row reader requires each selected column to exist and match the row schema. It validates physical type, logical type, and required or optional repetition.

For files whose schema evolves over time, pass ParquetSchemaEvolutionOptions to CreateRowReader. The options can allow selected compatibility changes, such as materializing a default value for a missing column or reading a required file column into a nullable property.