正在从HDF5数据集中读取字符串数组
本文关键字:集中 读取 字符串 数组 数据集 数据 HDF5 | 更新日期: 2023-09-27 18:00:14
我正试图将C#中的HDF5文件中的字符串数据集读取到字符串数组中。我能够使用以下代码读取数据集:
//read the no of rows and columns
var datasetID = H5D.open(fileId,"dimensions");
var dataTypeId = H5D.getType(datasetID);
var dataType = H5T.getClass(dataTypeId);
var length = H5T.getSize(dataTypeId);
int[] dDim = new int[length];
H5D.read(datasetID, dataTypeId, new H5Array<int>(dDim));
我试图对字符串数据集做同样的操作,但我将所有值初始化为null。所以我引用了这个链接(https://www.mail-archive.com/hdf-forum@hdfgroup.org/msg02980.html)。我可以将它们作为字节读取,但我不知道字节数组应该初始化到什么大小。我现在要读取的字符串代码是:
//read string
datasetID = H5D.open(fileId, "names");
var dataSpaceId = H5D.getSpace(datasetID);
long[] dims = H5S.getSimpleExtentDims(dataSpaceId);
dataTypeId = H5T.copy(H5T.H5Type.C_S1);
//hard coding the no of string to read (213)
byte[] buffer = new byte[dims[0]*213];
Console.WriteLine(dims[0]);
H5D.read(datasetID, dataTypeId, new H5Array<byte>(buffer));
Console.WriteLine(System.Text.ASCIIEncoding.ASCII.GetString(buffer)); `.
如果您事先不知道数据类型,请尝试以下代码。对于数据类型,它是不完整的,但它很容易修改:
public static Array Read1DArray(this H5FileId fileId, string dataSetName)
{
var dataset = H5D.open(fileId, dataSetName);
var space = H5D.getSpace(dataset);
var dims = H5S.getSimpleExtentDims(space);
var dtype = H5D.getType(dataset);
var size = H5T.getSize(dtype);
var classID = H5T.getClass(dtype);
var rank = H5S.getSimpleExtentNDims(space);
var status = H5S.getSimpleExtentDims(space);
// Read data into byte array
var dataArray = new Byte[status[0]*size];
var wrapArray = new H5Array<Byte>(dataArray);
H5D.read(dataset, dtype, wrapArray);
// Convert types
Array returnArray = null;
Type dataType = null;
switch (classID)
{
case H5T.H5TClass.STRING:
dataType = typeof(string);
break;
case H5T.H5TClass.FLOAT:
if (size == 4)
dataType = typeof(float);
else if (size == 8)
dataType = typeof(double);
break;
case H5T.H5TClass.INTEGER:
if (size == 2)
dataType = typeof(Int16);
else if (size == 4)
dataType = typeof(Int32);
else if (size == 8)
dataType = typeof(Int64);
break;
}
if (dataType == typeof (string))
{
var cSet = H5T.get_cset(dtype);
string[] stringArray = new String[status[0]];
for (int i = 0; i < status[0]; i++)
{
byte[] buffer = new byte[size];
Array.Copy(dataArray, i*size, buffer, 0, size);
Encoding enc = null;
switch (cSet)
{
case H5T.CharSet.ASCII:
enc = new ASCIIEncoding();
break;
case H5T.CharSet.UTF8:
enc = new UTF8Encoding();
break;
case H5T.CharSet.ERROR:
break;
}
stringArray[i] = enc.GetString(buffer).TrimEnd(''0');
}
returnArray = stringArray;
}
else
{
returnArray = Array.CreateInstance(dataType, status[0]);
Buffer.BlockCopy(dataArray, 0, returnArray, 0, (int) status[0]*size);
}
H5S.close(space);
H5T.close(dtype);
H5D.close(dataset);
return returnArray;
}
您的开始非常有帮助!有了它和HDF5示例代码的一些帮助,我能够想出一些通用的扩展,这将把你的代码简化为:
//read string
string[] datasetValue = fileId.Read1DArray<string>("names");
扩展看起来像这样(这是,或者应该是,与引用的问题完全相同。):
public static class HdfExtensions
{
// thank you https://stackoverflow.com/questions/4133377/splitting-a-string-number-every-nth-character-number
public static IEnumerable<String> SplitInParts(this String s, Int32 partLength)
{
if (s == null)
throw new ArgumentNullException("s");
if (partLength <= 0)
throw new ArgumentException("Part length has to be positive.", "partLength");
for (var i = 0; i < s.Length; i += partLength)
yield return s.Substring(i, Math.Min(partLength, s.Length - i));
}
public static T[] Read1DArray<T>(this H5FileId fileId, string dataSetName)
{
var dataset = H5D.open(fileId, dataSetName);
var space = H5D.getSpace(dataset);
var dims = H5S.getSimpleExtentDims(space);
var dataType = H5D.getType(dataset);
if (typeof(T) == typeof(string))
{
int stringLength = H5T.getSize(dataType);
byte[] buffer = new byte[dims[0] * stringLength];
H5D.read(dataset, dataType, new H5Array<byte>(buffer));
string stuff = System.Text.ASCIIEncoding.ASCII.GetString(buffer);
return stuff.SplitInParts(stringLength).Select(ss => (T)(object)ss).ToArray();
}
T[] dataArray = new T[dims[0]];
var wrapArray = new H5Array<T>(dataArray);
H5D.read(dataset, dataType, wrapArray);
return dataArray;
}
public static T[,] Read2DArray<T>(this H5FileId fileId, string dataSetName)
{
var dataset = H5D.open(fileId, dataSetName);
var space = H5D.getSpace(dataset);
var dims = H5S.getSimpleExtentDims(space);
var dataType = H5D.getType(dataset);
if (typeof(T) == typeof(string))
{
// this will also need a string hack...
}
T[,] dataArray = new T[dims[0], dims[1]];
var wrapArray = new H5Array<T>(dataArray);
H5D.read(dataset, dataType, wrapArray);
return dataArray;
}
}