A pure C# library for reading and writing NetCDF files (classic NC3 and HDF5-based NC4) with no native dependencies.
$ dotnet add package SwatRecords.NetCDFA pure C# library for reading and writing NetCDF files with no native dependencies. Supports both classic (NC3) and HDF5-based (NC4) formats.
dotnet add package SwatRecords.NetCDF
Open any NetCDF file — the format is auto-detected from magic bytes:
```csharp
using SwatRecords.NetCDF;
using var file = NetCdfFile.Open("data.nc");
// Inspect metadata
Console.WriteLine(file.Format); // Classic, NetCdf4, etc.
Console.WriteLine(file.Dimensions["time"].Length); // 24
Console.WriteLine(file.Attributes["Conventions"].GetValue<string>()); // "CF-1.7"
// Read variable data
var temp = file.Variables["temperature"];
Console.WriteLine(temp.DataType); // Float
Console.WriteLine(temp.Rank); // 3
Console.WriteLine(string.Join(", ", temp.Shape)); // 24, 113, 521
float[] allData = temp.Read<float>();
// Slice: read a subset with origin and shape
float[] slice = temp.Read<float>(
origin: [0, 10, 20],
shape: [1, 5, 10]);
// Slice with stride: read every 2nd element along each axis
float[] strided = temp.Read<float>(
origin: [0, 0, 0],
shape: [12, 57, 261],
stride: [2, 2, 2]);
```
## Writing
Create new NetCDF files using the builder pattern:
```csharp
using SwatRecords.NetCDF;
using SwatRecords.NetCDF.Model;
using var builder = NetCdfFile.Create("output.nc", NetCdfFormat.NetCdf4);
// Define dimensions
builder.AddDimension("latitude", 3);
builder.AddDimension("longitude", 4);
builder.AddUnlimitedDimension("time");
// Add global attributes
builder.AddGlobalAttribute("Conventions", "CF-1.7");
builder.AddGlobalAttribute("title", "Example dataset");
// Add coordinate variables
builder.AddVariable("latitude", NetCdfDataType.Double, "latitude")
.AddAttribute("units", "degrees_north")
.WriteData(new double[] { 45.0, 46.0, 47.0 });
builder.AddVariable("longitude", NetCdfDataType.Double, "longitude")
.AddAttribute("units", "degrees_east")
.WriteData(new double[] { -110.0, -109.0, -108.0, -107.0 });
// Add a data variable
builder.AddVariable("temperature", NetCdfDataType.Float, "time", "latitude", "longitude")
.AddAttribute("units", "K")
.AddAttribute("long_name", "2 metre temperature")
.WriteData(new float[2 * 3 * 4]); // 2 time steps x 3 lat x 4 lon
builder.Save();
```
### Writing Classic (NC3) Format
```csharp
using var builder = NetCdfFile.Create("output.nc", NetCdfFormat.Classic);
// Same API — format is selected at creation time
```
## Supported Formats
| Format | Read | Write |
|---|---|---|
| Classic (CDF-1) | Yes | Yes |
| 64-bit Offset (CDF-2) | Yes | Yes |
| 64-bit Data (CDF-5) | Yes | No |
| NetCDF-4 (HDF5) | Yes | Yes |
| NetCDF-4 Classic Model | Yes | No |
## Supported Data Types
`Byte`, `UByte`, `Char`, `Short`, `UShort`, `Int`, `UInt`, `Float`, `Double`, `Int64`, `UInt64`, `String`
## Dependencies
- [PureHDF](https://github.com/Apollo3zehn/PureHDF) for HDF5 support (no native binaries required)
## Building and Publishing
### Build the NuGet package
```
dotnet pack SwatRecords.NetCDF/SwatRecords.NetCDF.csproj -c Release
```
The `.nupkg` file will be created at `SwatRecords.NetCDF/bin/Release/SwatRecords.NetCDF.<version>.nupkg`.
### Publish to nuget.org
1. Get an API key from [nuget.org/account/apikeys](https://www.nuget.org/account/apikeys).
2. Push the package:~~~~
```
dotnet nuget push SwatRecords.NetCDF/bin/Release/SwatRecords.NetCDF.1.0.0.nupkg \
--api-key <YOUR_API_KEY> \
--source https://api.nuget.org/v3/index.json
```
### Publish to a private feed
```
dotnet nuget push SwatRecords.NetCDF/bin/Release/SwatRecords.NetCDF.1.0.0.nupkg \
--api-key <YOUR_API_KEY> \
--source https://your-feed-url/v3/index.json
```
### Bump the version
Update the `<Version>` property in `SwatRecords.NetCDF/SwatRecords.NetCDF.csproj` before packing a new release:
```xml
<Version>1.1.0</Version>
```
## License
[MIT](LICENSE)~~~~