Mixing strings and floats in a compound datatype with HDF5 DotNet Wrapper

Hello all,

I am trying to create a Table of CompoundData type that contains both
strings and floats with the C# wrapper, but having great difficulty. In the
example code below, I am trying to insert a single row with 2 columns, the
first one being a string, and the second one being a float.

The float always comes through just fine, but the value in the string cell
always ends up being a symbol. I am using HDFView to look at my h5 files.

What am I doing wrong?

[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct struct1 {
  public char* measurand;
  public float rate;
}

public static void Main(string[] args){

  FileInfo h5 = new FileInfo("myCSharp.h5");
  if (h5.Exists) {
    h5.Delete();
  }
  H5FileId fileId = H5F.create("myCSharp.h5",
                 H5F.CreateMode.ACC_TRUNC);
  H5F.close(fileId);

   fileId = H5F.open("myCSharp.h5",
                 H5F.OpenMode.ACC_RDWR);

   string test = "foo";
   
   uint len = (uint)test.Length+1;

   H5DataTypeId stringID = H5T.copy(H5T.H5Type.C_S1);
  H5T.setSize(stringID, len);
   H5DataTypeId tid1 =
H5T.create(H5T.CreateClass.COMPOUND,(uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(struct1)));
  H5T.insert(tid1, "Measurand", 0, stringID);
  H5T.insert(tid1, "Rate", len, H5T.H5Type.NATIVE_FLOAT);

  const int DATA_ARRAY_LENGTH = 12;

  // Rank is the number of dimensions of the data array.
  const int RANK = 1;
  ulong[] attributeDims = new ulong[RANK];
  attributeDims[0] = DATA_ARRAY_LENGTH;

   H5DataSpaceId spaceId = H5S.create_simple(RANK, attributeDims);
   H5DataSetId dataSetId = H5D.create(fileId, "/dictionaries",
                     tid1, spaceId);

  struct1[] dset_data = new struct1[DATA_ARRAY_LENGTH];
  
  struct1 foo = new struct1();
  foo.measurand = test;
  foo.rate = 125.0f;
  byte[] bytes = StructureToByteArray(foo);

    GCHandle pinnedPacket = GCHandle.Alloc(bytes, GCHandleType.Pinned);
struct1 msg = (struct1)Marshal.PtrToStructure(
pinnedPacket.AddrOfPinnedObject(),
typeof(struct1));
pinnedPacket.Free();
Console.WriteLine(msg.measurand);

unsafe
{
  IntPtr ipp =
System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(test);
   dset_data[0].measurand = (char*)ipp;
   dset_data[0].rate = 125.0f;

}

  H5D.write(dataSetId, tid1,
            new H5Array<struct1>(dset_data));
  H5F.close(fileId);
}

···

--
View this message in context: http://hdf-forum.184993.n3.nabble.com/Mixing-strings-and-floats-in-a-compound-datatype-with-HDF5-DotNet-Wrapper-tp2466591p2466591.html
Sent from the hdf-forum mailing list archive at Nabble.com.

Hi,

I am not familiar with the .NET wrapper or C#, but in C, fixed length strings should be represented in memory as character arrays instead of char *'s. So assuming this translates to C#/.NET, either the struct should change to something like:

public struct struct1 {
  public char measurand[length];
  public float rate;
}

Or use a variable-length string in the datatype definition, i.e. H5T.setSize(stringID, H5T_VARIABLE);. Fixed length strings will have better performance and can be compressed, while variable length strings may be more flexible.

I hope this is helpful.

Thanks,
-Neil

···

On 02/10/2011 09:21 AM, npike wrote:

Hello all,

I am trying to create a Table of CompoundData type that contains both
strings and floats with the C# wrapper, but having great difficulty. In the
example code below, I am trying to insert a single row with 2 columns, the
first one being a string, and the second one being a float.

The float always comes through just fine, but the value in the string cell
always ends up being a symbol. I am using HDFView to look at my h5 files.

What am I doing wrong?

[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct struct1 {
  public char* measurand;
  public float rate;
}

public static void Main(string[] args){

  FileInfo h5 = new FileInfo("myCSharp.h5");
  if (h5.Exists) {
    h5.Delete();
  }
  H5FileId fileId = H5F.create("myCSharp.h5",
                 H5F.CreateMode.ACC_TRUNC);
  H5F.close(fileId);

   fileId = H5F.open("myCSharp.h5",
                 H5F.OpenMode.ACC_RDWR);

    string test = "foo";

    uint len = (uint)test.Length+1;

    H5DataTypeId stringID = H5T.copy(H5T.H5Type.C_S1);
  H5T.setSize(stringID, len);
    H5DataTypeId tid1 =
H5T.create(H5T.CreateClass.COMPOUND,(uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(struct1)));
  H5T.insert(tid1, "Measurand", 0, stringID);
  H5T.insert(tid1, "Rate", len, H5T.H5Type.NATIVE_FLOAT);

  const int DATA_ARRAY_LENGTH = 12;

  // Rank is the number of dimensions of the data array.
  const int RANK = 1;
  ulong[] attributeDims = new ulong[RANK];
  attributeDims[0] = DATA_ARRAY_LENGTH;

    H5DataSpaceId spaceId = H5S.create_simple(RANK, attributeDims);
    H5DataSetId dataSetId = H5D.create(fileId, "/dictionaries",
                     tid1, spaceId);

   struct1[] dset_data = new struct1[DATA_ARRAY_LENGTH];

   struct1 foo = new struct1();
  foo.measurand = test;
  foo.rate = 125.0f;
  byte[] bytes = StructureToByteArray(foo);

    GCHandle pinnedPacket = GCHandle.Alloc(bytes, GCHandleType.Pinned);
struct1 msg = (struct1)Marshal.PtrToStructure(
pinnedPacket.AddrOfPinnedObject(),
typeof(struct1));
pinnedPacket.Free();
Console.WriteLine(msg.measurand);

unsafe
  {
  IntPtr ipp =
System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(test);
    dset_data[0].measurand = (char*)ipp;
    dset_data[0].rate = 125.0f;

  }

  H5D.write(dataSetId, tid1,
            new H5Array<struct1>(dset_data));
  H5F.close(fileId);
}