当我将包含数组的结构写入HDF5数据集时遇到问题。首先,窗口表单不是以以下行开头:
H5T.insert(typeStruct, "string", 0, H5T.create_array(new H5DataTypeId(H5T.H5Type.C_S1), dims2));
窗口窗体至少从没有行开始,所以我认为定义复合数据类型有问题。我研究了手册和许多示例,但是仍然无法解决问题。我可以举一个使用复合数据类型在C#中编写具有多个数组的结构的示例吗?
using HDF5DotNet;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Reflection;
namespace WindowsFormsApplication1
{
public unsafe partial class Form1 : Form
{
public unsafe struct struct_TR
{
public string[] arr_currentLong;
public struct_TR(byte size_currentTime)
{
arr_currentLong = new string[size_currentTime];
}
}
public Form1()
{
InitializeComponent();
long ARRAY_SIZE = 255;
struct_TR structMade = new struct_TR(255);
for (int i = 0; i < 255; i++)
{
structMade.arr_currentLong[i] = i.ToString();
}
string currentPath = Path.GetDirectoryName(Application.ExecutablePath);
Directory.SetCurrentDirectory(currentPath);
H5FileId fileId = H5F.create(@"weights.h5", H5F.CreateMode.ACC_TRUNC);
long[] dims1 = { 1 };
long[] dims2 = { 1, ARRAY_SIZE };
H5DataSpaceId myDataSpace = H5S.create_simple(1, dims1);
H5DataTypeId string_type = H5T.copy(H5T.H5Type.C_S1);
H5DataTypeId array_tid1 = H5T.create_array(string_type, dims2);
H5DataTypeId typeStruct = H5T.create(H5T.CreateClass.COMPOUND, Marshal.SizeOf(typeof(struct_TR)));
H5T.insert(typeStruct, "string", 0, H5T.create_array(new H5DataTypeId(H5T.H5Type.C_S1), dims2));
H5DataSetId myDataSet = H5D.create(fileId, "/dset", typeStruct, myDataSpace);
H5D.writeScalar<struct_TR>(myDataSet, typeStruct, ref structMade);
}
}
}
答案 0 :(得分:2)
我知道如何用数组保存结构的唯一方法是创建一个常量数组 例如,这是一个长度为4的结构。
[StructLayout(LayoutKind.Sequential)]
public struct Responses
{
public Int64 MCID;
public int PanelIdx;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public short[] ResponseValues;
}
在这里创建了一个包含数组的4个结构的数组:
responseList = new Responses[4] {
new Responses() { MCID=1,PanelIdx=5,ResponseValues=new short[4]{ 1,2,3,4} },
new Responses() { MCID=2,PanelIdx=6,ResponseValues=new short[4]{ 5,6,7,8}},
new Responses() { MCID=3,PanelIdx=7,ResponseValues=new short[4]{ 1,2,3,4}},
new Responses() { MCID=4,PanelIdx=8,ResponseValues=new short[4]{ 5,6,7,8}}
};
以下代码行将结构数组写入HDF5文件:
string filename = "testArrayCompounds.H5";
var fileId =H5F.create(filename, H5F.ACC_TRUNC);
var status = WriteCompounds(fileId, "/test", responseList);
H5F.close(fileId);
WriteCompounds方法如下:
public static int WriteCompounds<T>(hid_t groupId, string name, IEnumerable<T> list) //where T : struct
{
Type type = typeof(T);
var size = Marshal.SizeOf(type);
var cnt = list.Count();
var typeId = CreateType(type);
var log10 = (int)Math.Log10(cnt);
ulong pow = (ulong)Math.Pow(10, log10);
ulong c_s = Math.Min(1000, pow);
ulong[] chunk_size = new ulong[] { c_s };
ulong[] dims = new ulong[] { (ulong)cnt };
long dcpl = 0;
if (!list.Any() || log10 == 0) { }
else
{
dcpl = CreateProperty(chunk_size);
}
// Create dataspace. Setting maximum size to NULL sets the maximum
// size to be the current size.
var spaceId = H5S.create_simple(dims.Length, dims, null);
// Create the dataset and write the compound data to it.
var datasetId = H5D.create(groupId, name, typeId, spaceId, H5P.DEFAULT, dcpl);
IntPtr p = Marshal.AllocHGlobal(size * (int)dims[0]);
var ms = new MemoryStream();
BinaryWriter writer = new BinaryWriter(ms);
foreach (var strct in list)
writer.Write(getBytes(strct));
var bytes = ms.ToArray();
GCHandle hnd = GCHandle.Alloc(bytes, GCHandleType.Pinned);
var statusId = H5D.write(datasetId, typeId, spaceId, H5S.ALL,
H5P.DEFAULT, hnd.AddrOfPinnedObject());
hnd.Free();
/*
* Close and release resources.
*/
H5D.close(datasetId);
H5S.close(spaceId);
H5T.close(typeId);
H5P.close(dcpl);
Marshal.FreeHGlobal(p);
return statusId;
}
需要三个附加的帮助功能,此处显示两个:
private static long CreateType(Type t)
{
var size = Marshal.SizeOf(t);
var float_size = Marshal.SizeOf(typeof(float));
var int_size = Marshal.SizeOf(typeof(int));
var typeId = H5T.create(H5T.class_t.COMPOUND, new IntPtr(size));
var compoundInfo = Hdf5.GetCompoundInfo(t);
foreach (var cmp in compoundInfo)
{
H5T.insert(typeId, cmp.name, Marshal.OffsetOf(t, cmp.name), cmp.datatype);
}
return typeId;
}
private static long CreateProperty(ulong[] chunk_size)
{
var dcpl = H5P.create(H5P.DATASET_CREATE);
H5P.set_layout(dcpl, H5D.layout_t.CHUNKED);
H5P.set_chunk(dcpl, chunk_size.Length, chunk_size);
H5P.set_deflate(dcpl, 6);
return dcpl;
}
我还有一个ReadCompounds来读取hdf5文件。 CreateType方法中使用的Hdf5.GetCompoundInfo方法也很长。所以在这里我不会显示这些方法。
因此,用于编写某些结构的代码很多。 我制作了一个名为HDF5DotnetTools的库,该库使您可以轻松地读写类和结构。在这里您还可以找到ReadCompounds和GetCompoundInfo方法。
在HDF5DotnetTools的单元测试中,您还可以找到有关如何使用数组编写类的示例