After flailing around with HDF.PInvoke
for a while, I tried the HDF.PInvoke.NETStandard
Nuget package. Visual Studio was able to resolve my namespace reference (using HDF.PInvoke
).
For a basic idea of how to open files, groups, and datasets, I read through the HDF5 User Guide, specifically sections
- The HDF5 File
- HDF5 Groups
- HDF5 Datasets
I used the Object Browser in Visual Studio to browse the API for methods, enums, etc. referenced in the User Guide above. The names match closely. You can get this info from the HDF.PInvoke.NETStandard API reference, but there’s no additional info there, so you might as well use the IDE.
Finally, I wanted to read an array, but I couldn’t figure out how to pass in a pointer to an array in c#. Eventually, it occurred to me to check the unit tests for the API. There, I found you need to get a pinned GCHandle, and pass the AddrOfPinnedObject.
Here’s an example,
using HDF.PInvoke;
using System.Runtime.InteropServices;
namespace HDF5PInvokeHell
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("application start");
// Build file path
var folder = AppDomain.CurrentDomain.BaseDirectory;
string fileName = Path.Combine(folder, ".//resources//sample.h5");
// Open file
Console.WriteLine("opening file");
var fileId = H5F.open(fileName, H5F.ACC_RDONLY);
WriteStatusMessage(fileId, "open file");
// Open group
var groupName = "Group0/GroupA";
Console.WriteLine($"opening group: {groupName}");
var groupId = H5G.open(fileId, groupName);
WriteStatusMessage(groupId, "open group");
// open dataset
Console.WriteLine("opening dataset");
var datasetId = H5D.open(groupId, "Dataset0", H5F.ACC_RDONLY);
WriteStatusMessage(datasetId, "open dataset");
// get dataset type
Console.WriteLine("getting datatype id");
var datatypeId = H5D.get_type(datasetId);
WriteStatusMessage(datatypeId, "get datatype id");
// get datatype class id
Console.WriteLine("getting datatype class id");
var datatypeClassId = H5T.get_class(datatypeId);
WriteStatusMessage((int)datatypeClassId, "get datatype class id");
// read dataset
Console.WriteLine("reading dataset");
var myArray = new float[512, 512];
var myArrayHandle = GCHandle.Alloc(myArray, GCHandleType.Pinned);
WriteStatusMessage(H5D.read(datasetId, H5T.NATIVE_FLOAT, H5S.ALL, H5S.ALL, H5P.DEFAULT, myArrayHandle.AddrOfPinnedObject()), "read dataset");
// close dataset
Console.WriteLine("closing dataset");
WriteStatusMessage(H5D.close(datasetId), "close dataset");
// close group
Console.WriteLine($"closing group: {groupName}");
WriteStatusMessage(H5G.close(groupId), "close group");
// close file
Console.WriteLine("closing file");
WriteStatusMessage(H5F.close(fileId), "close file");
Console.WriteLine("Application end");
}
private static void WriteStatusMessage(long status, string message)
{
// H5* methods that return a status code follow the convention:
// success = 0
// failure = -1
// H5* methods that return a value follow a similar convention:
// readSuccess => value = value
// readFailure => value < 0
if (status >= 0)
Console.WriteLine($"{message}: OK");
else
Console.WriteLine($"{message}: FAIL");
}
}
}