dotnet add package Pqax --version 0.2.2
                    
NuGet\Install-Package Pqax -Version 0.2.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Pqax" Version="0.2.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Pqax" Version="0.2.2" />
                    
Directory.Packages.props
<PackageReference Include="Pqax" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Pqax --version 0.2.2
                    
#r "nuget: Pqax, 0.2.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Pqax@0.2.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Pqax&version=0.2.2
                    
Install as a Cake Addin
#tool nuget:?package=Pqax&version=0.2.2
                    
Install as a Cake Tool

Pqax

Reads, writes, and validates PQAX files in .NET. A PQAX file holds the footprint of a set of Parquet tables: how much space the data takes and how it is arranged, without the data. It is a zip of JSON tables, defined by the serialization and the object model of PQAX, which the conformance kit turns into rules, a schema, and samples.

Targets netstandard2.0, so that .NET Framework hosts can use it, and net8.0
Dependencies None on net8.0. On netstandard2.0, System.Text.Json 8.0.5 and the packages that it brings.
Reads Format versions whose first number, the text before the first dot, is 0: 0.1 and 0.2, and also 0.9, 0, or 0.1.2
Writes Format version 0.2
Validates Every rule of the conformance kit, with its code

Install

dotnet add package Pqax

The namespace is Pqax. From a clone of the repository, reference src/dotnet/Pqax/Pqax.csproj instead. A .NET Framework application needs binding redirects: read the section .NET Framework below.

Open a file

using Pqax;

// A PQAX file of its own.
using (PqaxDocument doc = PqaxDocument.Open("footprint.pqax"))
{
    Console.WriteLine($"PQAX {doc.Manifest.FormatVersion}, level {doc.Manifest.Collection.Level}, {doc.Summary.Tables.Count} tables");
}

// The footprint that a VPAX file holds as the part Footprint.pqax.
try
{
    using (PqaxDocument doc = PqaxDocument.OpenEmbedded("model.vpax"))
    {
        Console.WriteLine($"{doc.EmbeddedPart}, {doc.EmbeddedCompression}");
    }
}
catch (PqaxFormatException e) when (e.Code == "embedded.partMissing")
{
    Console.WriteLine("The VPAX file has no footprint.");
}
Method What it reads
PqaxDocument.Open(path), Open(stream, leaveOpen) The central directory of the zip, manifest.json, and summary.json. Nothing else. A stream that cannot seek is copied into memory first.
PqaxDocument.OpenEmbedded(vpaxPath, partName), OpenEmbedded(stream, partName, leaveOpen) The same, for the PQAX file that a VPAX file holds as the part Footprint.pqax. A stored part is read in place, a deflated part is inflated in memory first. EmbeddedPart gives the name of the part and EmbeddedCompression gives stored or deflated; both are null for a PQAX file of its own.

Read the tables

using System.Linq;

using (PqaxDocument doc = PqaxDocument.OpenEmbedded("model.vpax"))
{
    foreach (TableRow table in doc.Summary.Tables)
    {
        Console.WriteLine($"{table.Name}: {table.Format}, {table.FileCount} files, {table.FileSize} bytes, depth {table.DetailDepth}");
        foreach (ColumnRow column in doc.Summary.Columns.Where(c => c.Table == table.Id))
        {
            Console.WriteLine($"  {column.Name} {column.DataType}: {column.CompressedSize} bytes");
        }
    }

    // RowCount reads nothing: it adds up the rows that the manifest states.
    if (doc.RowCount("columnChunks") > 0)
    {
        // A detail table is read from its parts on the first call, and then kept.
        PqaxTable<ColumnChunkRow> chunks = doc.ReadColumnChunks();
        Console.WriteLine($"{chunks.Count} column chunks, {chunks.Sum(c => c.CompressedSize ?? 0)} bytes");
    }
}
Member of PqaxDocument Tables Read
Summary The 15 summary tables, one property each: Sources, Tables, Columns, PartitionSpecs, PartitionFields, SortOrders, SortFields, PhysicalSchemas, PhysicalColumns, Writers, Operations, Issues, ModelBindings, TableBindings, ColumnBindings When the document opens
ReadPartitions(), ReadFiles(), ReadRowGroups(), ReadColumnChunks(), ReadDeleteFiles(), ReadCommits() The 6 detail tables, each with all its parts concatenated in the order of the manifest On the first call, then kept
ReadRaw(name) Any table, known or not, with every field as JSON values On every call
RowCount(name) The rows of any table, as the manifest states them Never
Manifest Format, version, collection, obfuscation fields, parts, and the members that this version does not know, in Extensions When the document opens

A table is a PqaxTable<TRow>, which is also an IReadOnlyList<TRow>: Name, Count, Rows, an indexer, FindById(id), and ExtraFields, the fields that this version does not know, with one JsonElement? for each row. A table that the file does not have is empty.

A row is a class with one property for each field of the object model, named as in the file with a capital first letter: ColumnRow.DataType for dataType. The types:

Type in the model Type in C#
integer long?
id long, 0 when the file gives none
reference long?, the id of the row it points to: ColumnRow.Table, ColumnChunkRow.RowGroup
list of references IReadOnlyList<long>?
string string?
boolean bool?
timestamp DateTimeOffset?, in UTC
list of string IReadOnlyList<string>?. The format allows a null element only in PartitionRow.Values, for a null partition value.
map of string to string IReadOnlyDictionary<string, string>?
Distribution, DeltaDetails, IcebergDetails Classes of the same names. Their members that this version does not know are in Extensions.

Rows, nested objects, and CollectionInfo have value equality: two rows are equal when every field is equal. Lists that the reader returns may be shared between rows: do not cast them to arrays and change them.

The reader is more tolerant than the validator. A field that a part leaves out, or a value of another JSON type than the model's, reads as null. What this version does not know is kept in ExtraFields, ReadRaw, and Extensions, or ignored. The documentation of PqaxDocument has the details.

Follow a reference

A reference holds the id of a row of another table. FindById finds that row, and gives null when the reference is null or the file has no such row. A table builds the index of its ids on the first call.

using (PqaxDocument doc = PqaxDocument.Open("footprint.pqax"))
{
    PqaxTable<FileRow> files = doc.ReadFiles();
    PqaxTable<RowGroupRow> rowGroups = doc.ReadRowGroups();
    foreach (ColumnChunkRow chunk in doc.ReadColumnChunks())
    {
        var physical = doc.Summary.PhysicalColumns.FindById(chunk.PhysicalColumn);
        var column = doc.Summary.Columns.FindById(physical?.Column);
        var file = files.FindById(rowGroups.FindById(chunk.RowGroup)?.File);
        Console.WriteLine($"{file?.Path} {column?.Name}: {chunk.CompressedSize} bytes");
    }
}

There is no index in the other direction: the columns of a table are doc.Summary.Columns.Where(c => c.Table == table.Id), as in the previous sample.

Validate

ValidationResult result = PqaxValidator.ValidateEmbedded("model.vpax");
Console.WriteLine(result);   // "valid, N checks" or "invalid, N issues in M checks"
foreach (ValidationIssue issue in result.Issues)
{
    Console.WriteLine($"{issue.Code}: {issue.Message}");
}
Member What it does
PqaxValidator.Validate(path), Validate(stream) Checks a PQAX file
PqaxValidator.ValidateEmbedded(vpaxPath, partName), ValidateEmbedded(stream, partName) Checks the PQAX file inside a VPAX file
ValidationResult IsValid, Issues, and ChecksRun
ValidationIssue Code, Message, and when they apply Part, Table, and Field. ToString() gives them on one line.

The codes are those of the rules of the conformance kit: container.*, json.*, manifest.*, part.*, table.*, depth.*, and totals.*, and embedded.partMissing when a VPAX file has no part with the name of the footprint. The validator reports every issue instead of stopping at the first, with one issue for each rule, part, table, and field, and the count of the values in the message. It skips a rule that an earlier failure makes impossible to evaluate. A file that is not a zip is container.manifestMissing, and so is a VPAX file given to Validate. Messages hold numbers and names of the format, never a name or a value that comes from the data.

The validator never throws PqaxFormatException: it throws only for a null argument, and when the file cannot be read at all. A file does not have to be valid to be read: the reader opens most invalid files.

Measure the tables, the columns, and the collection

StorageMeasures computes every derived measure of section 10 of the object model for the tables, the columns, and the collection, with the names and the numbers of the storage views: the storage stack with its waste, its overhead, and the share of each component, the file sizes, the small files, and the V-Order shares, the history with VACUUM and OPTIMIZE, the ratios, the partitions, the measures of each column, and the totals of the collection. Only the two measures over a set of columns, which the treemap of the views draws, are not here.

using PqaxDocument doc = PqaxDocument.Open("footprint.pqax");
FootprintMeasures measures = StorageMeasures.Compute(doc);       // reads the files and partitions tables when the file has them
foreach (TableStorage table in measures.Tables.OrderByDescending(t => t.Stack.Waste))
{
    Console.WriteLine($"{table.Label}: {table.Stack.Waste:N0} bytes of waste, {table.Stack.WasteShare:P1} of the data, " +
        $"median file {table.Files.Median:N0} bytes, V-Ordered {table.Files.VOrderShare:P0}, last VACUUM {table.Maintenance.LastVacuumAt}");
}
foreach (ColumnStorage column in measures.Columns.Where(c => c.NullShare > 0.5))
{
    Console.WriteLine($"{column.Label}: {column.NullShare:P0} null");
}
Console.WriteLine($"{measures.Collection.Tables} tables, {measures.Collection.Footprint:N0} bytes stored");
Member What it is
StorageMeasures.Compute(document, options) The measures of every table, column, and of the collection, from the summary and the files and partitions tables. A detail table that cannot be read becomes a warning, and the measures use the totals of the summary.
StorageMeasures.ForTables(summary, files, collection, options, partitions) The measures of the tables, for a caller that read the tables
StorageMeasures.ForColumns(summary), ForCollection(summary, tables) The measures of the columns, and those of the collection from the tables that ForTables returned
StorageMeasures.StackOf, DeletedEstimate, SmallShareAtLeast, CommitsPerDay, DaysBetween, Ratio The derived values, one function each, as stackOf, deletedEstimate, smallShareAtLeast, commitsPerDay, daysBetween, and ratio of the views
StorageMeasures.StackComponents, WasteComponents, OverheadComponents The names of the components: live, nonLive, unreferenced, deleted, stale, metadata, footers; the first four after live are the waste, the last two the overhead
FootprintMeasures Tables, Columns, Collection, FilesRead, Warnings
TableStorage Id, Row, Name, Label, RowCount, FileCount, FileSize, Stack, SmallFiles, TinyFiles, Files, Measures, Maintenance, Partitions, and WriteTo(Utf8JsonWriter), which writes the JSON of pqax tables --json for one table
StorageStack The seven components, DeletedSource, Listed, Data, Total, Waste, Overhead, WasteShare, OverheadShare, Component(key), and Share(key), the share of a component
SmallFiles Threshold, Count from the files table, ShareAtLeast
FileMeasures Count, Sum, Minimum, FirstQuartile, Median, ThirdQuartile, Maximum, VOrderShare, VOrderBytesShare
TableMeasures CompressionRatio, DeletedRowShare, AverageFileSize, AverageRowGroupRows, FooterCoverage, StaleColumnShare, NonLiveShare, AveragePartitionSize, DictionaryFallbackShare
MaintenanceMeasures LastCommitAt, CommitsPerDay, DaysSinceLastCommit, HasVacuum, LastVacuumAt, HasOptimize, LastOptimizeAt
PartitionMeasures Count, Kept, OldestModifiedAt, NewestModifiedAt
ColumnStorage Id, Row, Table, Name, Label, NullShare, CompressionRatio, DictionaryShare, DictionaryFallbackShare, AverageValueLength, FilesWithoutColumnShare
CollectionMeasures Sources, Tables, Columns, Files, FileSize, RowCount, Footprint, Waste, Overhead, Depths
MeasureOptions SmallFileSize, 128 MiB by default, and TinyFileSize, 8 MiB

A value that cannot be computed is null, never 0: a stack component whose field the file lacks, such as the unreferenced files of a file of format 0.1, is null. The waste, the overhead, and the total count such a component as 0, as the views do, and are null only when every component they add is absent. The conformance kit holds the measures of the views for every sample, in conformance/expected/measures, and the tests compare these with them.

Compare two footprints

StorageDiff compares two footprints of the same lakehouse taken at different times, as section 13 of the object model proposes: the tables and the columns added, removed, and kept, and for every kept one the older value, the newer value, and the delta of each total of section 6 and of each measure of section 10. A table is the same table when its TableId is, and otherwise, when one of the two has none, when its source, namespace, and name are; a column when its FieldId is, and otherwise by name; a partition by its values, a file by its path, and a commit by its CommitId.

using PqaxDocument older = PqaxDocument.Open("monday.pqax");
using PqaxDocument newer = PqaxDocument.Open("friday.pqax");
FootprintDiff diff = StorageDiff.Compare(older, newer);
foreach (TableChange change in StorageDiff.Rank(diff, "total", top: 10))
{
    if (change.Kept is { } kept)
    {
        Console.WriteLine($"{kept.Newer.Label}: {kept.Measure("stack.total")!.Delta:N0} bytes, {kept.Files?.Added} files added, {kept.Columns.Added.Count} columns added");
    }
    else
    {
        Console.WriteLine($"{change.Label} {change.Kind}{(change.Entry!.Recreated ? ", recreated" : string.Empty)}: {change.Entry.Table.Total:N0} bytes");
    }
}
Member What it is
StorageDiff.Compare(older, newer, options) The comparison. It computes the measures of both documents with StorageMeasures.Compute, and reads their files, partitions, and commits tables when they have rows.
StorageDiff.Rank(diff, order, top) The changes in one order, as TableChange: total, waste, rows, or files by the size of the change, the largest first, or name
StorageDiff.Orders total, waste, rows, files, name
FootprintDiff Older and Newer, the measures of each document; SmallFileSize, TinyFileSize; Collection, the change of the measures of the collection and of the tables at each depth; Added, Removed, Kept; ChangedCount; CollectionValue(name)
ValueChange Name, Older, Newer, Delta, IsChanged. A value is a long, a double, a bool, a string, a DateTimeOffset, a list of strings, or null. The delta of a time is in milliseconds; a boolean, a text, and a list have none, and the delta is null when either value is.
TableEntry A table added or removed: Table and Recreated, true when a table with the same source, namespace, and name was removed and added with another TableId
TableSide Id, Row, Label, Name, Namespace, TableId, SnapshotId, DetailDepth, ColumnCount, FileCount, FileSize, RowCount, and the Total and Waste of its stack
KeptTable MatchedBy (tableId or name), Renamed, IsChanged, Older, Newer, Totals, Measures, Columns, and Files, Partitions, Commits, null when the two footprints do not both keep them; Total(name) and Measure(name)
ColumnChanges Added and Removed, as ColumnSide, and Kept, as KeptColumn
ColumnSide, KeptColumn Id, Row, Label, Name, FieldId, DataType, IsNullable, CompressedSize; and MatchedBy (fieldId or name), Renamed, IsChanged, Older, Newer, Totals, Measures
DetailChanges Added, Removed, Kept, and for the files and the partitions Changed, AddedFileSize, and RemovedFileSize
TableChange Kind (added, removed, kept), Entry or Kept, and Label

A kept table is changed when its name, its SnapshotId, a total, a column, a file, a partition, or a commit differs; a measure alone does not make it changed, since the days since the last commit move with the time of the collection. The totals keep the names of the fields, with the members of a distribution as fileSizes.median, and the measures the paths of the JSON of the measures, such as stack.waste. pqax diff of Pqax.Cli writes the comparison as a report or as JSON. The conformance kit has two footprints with known differences and their expected diff, in conformance/expected/diff, and the tests compare the comparison with it.

Write

var builder = new FootprintBuilder(new CollectionInfo { CollectorApp = "MyTool", CollectorAppVersion = "1.0", Level = 2, CompletedAt = DateTimeOffset.UtcNow });
long source = builder.AddSource(new SourceRow { Kind = "Storage folder", Name = "sales" });
long table = builder.AddTable(new TableRow { Source = source, Name = "orders", Format = "Delta", DetailDepth = "Files", FileCount = 1, FileSize = 1024 });
builder.AddColumn(new ColumnRow { Table = table, Name = "id", DataType = "long" });
builder.AddFile(new FileRow { Table = table, Path = "part-0.parquet", FileSize = 1024 });
builder.Write("orders.pqax");

There is one Add method for each of the 21 tables. For a table with ids, it keeps a positive id that the row brings, gives a row whose id is 0 the next free id, one more than the largest id so far, and returns the id. For a table without ids, it returns the position of the row, from 0. The caller puts the ids in the references of other rows. The builder keeps the row instance itself, so a property set after Add, such as the clustering columns of a table once its columns have ids, is written.

Write refuses a table with the same id in two rows, or with an id that is not positive: it throws InvalidOperationException, with the table and the id in the message, before it writes anything. Apart from the ids, the builder does not check what it writes. Validate the file when it matters.

The file has manifest.json, then summary.json, then the parts of the detail tables, with at most Options.RowsPerPart rows in a part: 250,000, the most that the format allows, by default. The JSON is compact UTF-8, deflated at Options.CompressionLevel, Optimal by default. Every entry has the date of Collection.CompletedAt, so the same footprint gives the same bytes on the same .NET runtime. The documentation of FootprintBuilder has the details.

FootprintBuilder.From(document) copies every table of a document, with its ids, the fields and tables that this version does not know, the members of the manifest and of nested objects that it does not know, the collection, and the obfuscation fields. A tool that rewrites a file starts there. The written file has format version 0.2, also when the document is a 0.1 file, and its detail parts are named after their tables.

Embed a footprint in a VPAX file

The package does not write VPAX files. A VPAX file is an Open Packaging Conventions package, and System.IO.Packaging adds the footprint to it as the part /Footprint.pqax, with the content type application/zip. Store the part without compression, so that a reader opens it in place.

using System.IO.Packaging;

static void AddFootprint(string vpaxPath, FootprintBuilder builder)
{
    var uri = new Uri("/" + PqaxDocument.FootprintPartName, UriKind.Relative);
    using (Package package = Package.Open(vpaxPath, FileMode.Open, FileAccess.ReadWrite))
    {
        if (package.PartExists(uri))
        {
            package.DeletePart(uri);
        }

        PackagePart part = package.CreatePart(uri, "application/zip", CompressionOption.NotCompressed);
        using (Stream stream = part.GetStream())
        {
            builder.Write(stream);
        }
    }
}

The part holds the same bytes as a .pqax file, so copying a file into the part works too. System.IO.Packaging is a NuGet package on .NET 8, and part of WindowsBase on .NET Framework.

Threads and disposal

Object Threads Lifetime
PqaxDocument Every member is safe from several threads. The reads of one document are serialized, so two threads that read two detail tables wait for each other. Dispose closes the file, or the stream unless leaveOpen is true. Manifest, Summary, RowCount, and the detail tables already read stay usable. A detail table not read yet, and ReadRaw, then throw ObjectDisposedException.
PqaxTable<TRow> and rows A table is safe to read from several threads, FindById included. Rows are plain mutable objects, without locks. A table outlives its document.
FootprintBuilder The Add methods and Write are safe from several threads. Do not change a row while Write runs. Nothing to dispose. Write can run more than once.
PqaxValidator Static, with no shared state It closes the file that it opens, and leaves a stream open.

A document opened from a path keeps the file open, shared with readers only, until it is disposed: dispose it before the file is written again. A footprint stored in a VPAX file keeps the VPAX file open the same way; a deflated one is inflated, and the VPAX file is closed at once. A document opened from a stream moves the position of the stream when it reads, so do not use that stream elsewhere while the document is open.

The I/O is synchronous. In an application with a user interface, open and read on a background thread: opening takes milliseconds, and reading 600,000 column chunks about a second, as the section Time shows.

.NET Framework

A .NET Framework application uses the netstandard2.0 build. The section Time has figures measured on .NET Framework 4.8.

Topic Detail
Dependencies System.Text.Json 8.0.5, which brings Microsoft.Bcl.AsyncInterfaces, System.Buffers, System.Memory, System.Numerics.Vectors, System.Runtime.CompilerServices.Unsafe, System.Text.Encodings.Web, System.Threading.Tasks.Extensions, and System.ValueTuple. They are copied next to the application.
Binding redirects Required. Pqax references System.Text.Json 8.0.0.0, and the package installs 8.0.0.5 on .NET Framework. System.Memory references an older System.Runtime.CompilerServices.Unsafe than the one installed. Without the redirects, Pqax fails with FileLoadException as soon as it needs System.Text.Json.
API No Span or Memory: strings, streams, nullable numbers, read-only lists and dictionaries, and JsonElement only for what this version does not know
C# The samples of this page compile with C# 7.3, the default for .NET Framework

An SDK-style project that builds an application generates the redirects, because AutoGenerateBindingRedirects is on by default for it. Another project adds them to its app.config. With no other package that brings later versions of these assemblies, they are:

<dependentAssembly>
  <assemblyIdentity name="System.Text.Json" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
  <bindingRedirect oldVersion="0.0.0.0-8.0.0.5" newVersion="8.0.0.5" />
</dependentAssembly>
<dependentAssembly>
  <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
  <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>

A library that another application loads, such as a plug-in, runs with the redirects of that application.

Errors

Exception When
PqaxFormatException The reader refuses a file, or a part of it. Code is the code of the rule, as in the next table.
ArgumentNullException An argument is null
IOException, such as FileNotFoundException, and UnauthorizedAccessException A file or a stream cannot be opened, read, or written
ObjectDisposedException A read, after Dispose, of a table that the document had not read before
InvalidOperationException Write finds an id that repeats in a table, or that is not positive
ArgumentException A path is empty, or Write gets a stream that cannot write
ArgumentOutOfRangeException Options.RowsPerPart outside 1 to 250,000, or an index outside a table

The reader refuses a file with a PqaxFormatException only in these cases:

Code When
container.manifestMissing The file is not a zip, or it has no manifest.json. For OpenEmbedded, also a VPAX file that is not a zip, or a part that cannot be inflated.
embedded.partMissing OpenEmbedded: the VPAX file has no part with the name of the footprint
manifest.format The format is not pqax
manifest.versionUnknown The first number of the format version is not 0
json.invalid A part that it reads is damaged or is not valid JSON. For a detail part, the read of that table fails, not the open.
manifest.partMissing A detail part that it reads is not in the archive. The read of that table fails, not the open.
container.zip64, container.method, container.encrypted The archive needs ZIP64 to be read, or a part that it reads needs ZIP64, uses a compression other than deflate, or is encrypted

What the package does not do

Not in the package Where it is
Collect a footprint from a lakehouse or a folder, or read Parquet and Delta files The package Pqax.Collector
The tree of the treemap, and the two measures over a set of columns that it draws The view model of @pqax/views. StorageMeasures has every other measure.
Write a VPAX file, or embed a footprint in one System.IO.Packaging, as above, and later the VPAX library
Obfuscate names Later, in the VPAX obfuscator, from FootprintBuilder.From
Asynchronous I/O Not in 0.2
Check the CRC of the zip entries Not done. Deflate finds most damage, and a damaged stored part fails as JSON.
A command line The package Pqax.Cli: pqax check, pqax info, and pqax tables

Limits

Limit Detail
Size of a part A part is read into memory whole, up to 1 GiB. A larger part fails with json.invalid. A part of 250,000 column chunks is about 20 MB of JSON.
Memory A row is an object. A column chunk takes about 270 bytes, so 600,000 column chunks hold about 155 MB. Equal strings and equal lists of strings, such as codecs and encodings, are shared.
Integers The writer does not check that an integer is within 2^53 - 1. The validator does.

Time

Measured on 7 October 2026 on one Windows 11 machine, with a file of 600,000 column chunks in three parts, 30,000 row groups, and 10,000 files: 6.2 MB.

Step .NET 8 .NET Framework 4.8
Write with FootprintBuilder 0.9 s 1.7 s
Open: directory, manifest, and summary 13 ms, 1.3 KB read 57 ms
Read 600,000 column chunks, first time in the process 0.7 to 0.9 s 1.1 s
Read 600,000 column chunks, warm 0.3 s 1.2 s
Validate 0.9 s 2.2 s
Product 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 is compatible.  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 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Pqax:

Package Downloads
Pqax.Collector

Collects the footprint of Delta tables from OneLake or from a local folder: reads the Delta logs and the Parquet footers, and writes a PQAX file. Parses Parquet footers itself, with no Parquet library.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.2 138 10/24/2026
0.2.1 137 10/24/2026
0.2.0 136 10/21/2026
0.1.2 133 10/21/2026
0.1.1 123 10/21/2026
0.1.0 131 10/21/2026