如何在 C# .NET 中读取 HDF5 可变长度字符串属性
How to read HDF5 variable length string attributes in C# .NET
使用C#中的HDF.PInvoke库,如何读取可变长度字符串,H5T_VARIABLE
,属性?
HDF5 文件如下所示:
GROUP "/" {
ATTRIBUTE "foo" {
DATATYPE H5T_STRING {
STRSIZE H5T_VARIABLE;
STRPAD H5T_STR_NULLTERM;
CSET H5T_CSET_ASCII;
CTYPE H5T_C_S1;
}
DATASPACE SCALAR
DATA {
(0): "bar"
}
}
}
正在尝试像这样读取属性 foo
:
long fileId = H5F.open("my-file.h5", H5F.ACC_RDWR);
long attrId = H5A.open(fileId, "foo");
long typeId = H5A.get_type(attrId);
H5A.info_t attrInfo = new H5A.info_t();
var info_result = H5A.get_info(attrId, ref attrInfo);
// Note sure if this `size` is useful.
// Docs say: For variable-length string datatypes, the returned value is
// the size of the pointer to the actual string, or sizeof(char *).
// This function does not return the size of actual variable-length
// string data.
// @See: https://support.hdfgroup.org/HDF5/doc/RM/RM_H5T.html#Datatype-GetSize
int size = H5T.get_size(typeId).ToInt32();
// Docs say: `data_size` indicates the size, in the number of characters,
// of the attribute.
// @See: https://support.hdfgroup.org/HDF5/doc/RM/RM_H5A.html#Annot-GetInfo
int data_size = (int)attrInfo.data_size;
// Docs say: In a C environment, variable-length strings will always be
// NULL-terminated, so the buffer to hold such a string must be
// one byte larger than the string itself to accommodate the NULL
// terminator.
// @See: https://support.hdfgroup.org/HDF5/doc/RM/RM_H5T.html#CreateVLString
IntPtr iPtr = Marshal.AllocHGlobal(data_size + 1); // Add one to fit NULL-terminator.
int read_result = H5A.read(attrId, typeId, iPtr);
if (H5T.is_variable_str(typeId) > 0)
{
Console.WriteLine("attribute value = {0}", Marshal.PtrToStringAnsi(iPtr));
}
控制台输出随机数据:
attribute value = @Ñ>←
看看 HDFql,因为这将使您在 C# 中处理 HDF 可变长度字符串时无需了解低级细节。下面是一个完整的示例,说明如何使用 HDFql 读取(和打印)存储在属性中的可变长度字符串(假设存在一个名为 my-file.h5
的 HDF 文件,并且它包含一个属性 foo
的变量-字符串长度):
// use HDFql namespace (make sure it can be found by the C# compiler)
using AS.HDFql;
public class Example
{
public static void Main(string []args)
{
// select (i.e. read) attribute "foo" (from HDF5 file "my-file.h5") and populate default cursor with its data
HDFql.Execute("SELECT FROM my-file.h5 foo");
// move default cursor to first position
HDFql.CursorFirst();
// display content of default cursor
System.Console.WriteLine(HDFql.CursorGetChar());
}
}
我从 Hdf5DotnetTools 库中找到了解决方案。
long fileId = H5F.open("my-file.h5", H5F.ACC_RDWR);
long attrId = H5A.open(fileId, "foo");
long typeId = H5A.get_type(attrId);
long spaceId = H5A.get_space(attrId);
long count = H5S.get_simple_extent_npoints(spaceId);
H5S.close(spaceId);
IntPtr[] dest = new IntPtr[count];
GCHandle handle = GCHandle.Alloc(dest, GCHandleType.Pinned);
H5A.read(attrId, typeId, handle.AddrOfPinnedObject());
var attrStrings = new List<string>();
for (int i = 0; i < dest.Length; ++i)
{
int attrLength = 0;
while (Marshal.ReadByte(dest[i], attrLength) != 0)
{
++attrLength;
}
byte[] buffer = new byte[attrLength];
Marshal.Copy(dest[i], buffer, 0, buffer.Length);
string stringPart = Encoding.UTF8.GetString(buffer);
attrStrings.Add(stringPart);
H5.free_memory(dest[i]);
}
handle.Free();
if (H5T.is_variable_str(typeId) > 0)
{
Console.WriteLine("attribute value = {0}", attrStrings[0]);
}
控制台正确输出:
attribute value = bar
使用C#中的HDF.PInvoke库,如何读取可变长度字符串,H5T_VARIABLE
,属性?
HDF5 文件如下所示:
GROUP "/" {
ATTRIBUTE "foo" {
DATATYPE H5T_STRING {
STRSIZE H5T_VARIABLE;
STRPAD H5T_STR_NULLTERM;
CSET H5T_CSET_ASCII;
CTYPE H5T_C_S1;
}
DATASPACE SCALAR
DATA {
(0): "bar"
}
}
}
正在尝试像这样读取属性 foo
:
long fileId = H5F.open("my-file.h5", H5F.ACC_RDWR);
long attrId = H5A.open(fileId, "foo");
long typeId = H5A.get_type(attrId);
H5A.info_t attrInfo = new H5A.info_t();
var info_result = H5A.get_info(attrId, ref attrInfo);
// Note sure if this `size` is useful.
// Docs say: For variable-length string datatypes, the returned value is
// the size of the pointer to the actual string, or sizeof(char *).
// This function does not return the size of actual variable-length
// string data.
// @See: https://support.hdfgroup.org/HDF5/doc/RM/RM_H5T.html#Datatype-GetSize
int size = H5T.get_size(typeId).ToInt32();
// Docs say: `data_size` indicates the size, in the number of characters,
// of the attribute.
// @See: https://support.hdfgroup.org/HDF5/doc/RM/RM_H5A.html#Annot-GetInfo
int data_size = (int)attrInfo.data_size;
// Docs say: In a C environment, variable-length strings will always be
// NULL-terminated, so the buffer to hold such a string must be
// one byte larger than the string itself to accommodate the NULL
// terminator.
// @See: https://support.hdfgroup.org/HDF5/doc/RM/RM_H5T.html#CreateVLString
IntPtr iPtr = Marshal.AllocHGlobal(data_size + 1); // Add one to fit NULL-terminator.
int read_result = H5A.read(attrId, typeId, iPtr);
if (H5T.is_variable_str(typeId) > 0)
{
Console.WriteLine("attribute value = {0}", Marshal.PtrToStringAnsi(iPtr));
}
控制台输出随机数据:
attribute value = @Ñ>←
看看 HDFql,因为这将使您在 C# 中处理 HDF 可变长度字符串时无需了解低级细节。下面是一个完整的示例,说明如何使用 HDFql 读取(和打印)存储在属性中的可变长度字符串(假设存在一个名为 my-file.h5
的 HDF 文件,并且它包含一个属性 foo
的变量-字符串长度):
// use HDFql namespace (make sure it can be found by the C# compiler)
using AS.HDFql;
public class Example
{
public static void Main(string []args)
{
// select (i.e. read) attribute "foo" (from HDF5 file "my-file.h5") and populate default cursor with its data
HDFql.Execute("SELECT FROM my-file.h5 foo");
// move default cursor to first position
HDFql.CursorFirst();
// display content of default cursor
System.Console.WriteLine(HDFql.CursorGetChar());
}
}
我从 Hdf5DotnetTools 库中找到了解决方案。
long fileId = H5F.open("my-file.h5", H5F.ACC_RDWR);
long attrId = H5A.open(fileId, "foo");
long typeId = H5A.get_type(attrId);
long spaceId = H5A.get_space(attrId);
long count = H5S.get_simple_extent_npoints(spaceId);
H5S.close(spaceId);
IntPtr[] dest = new IntPtr[count];
GCHandle handle = GCHandle.Alloc(dest, GCHandleType.Pinned);
H5A.read(attrId, typeId, handle.AddrOfPinnedObject());
var attrStrings = new List<string>();
for (int i = 0; i < dest.Length; ++i)
{
int attrLength = 0;
while (Marshal.ReadByte(dest[i], attrLength) != 0)
{
++attrLength;
}
byte[] buffer = new byte[attrLength];
Marshal.Copy(dest[i], buffer, 0, buffer.Length);
string stringPart = Encoding.UTF8.GetString(buffer);
attrStrings.Add(stringPart);
H5.free_memory(dest[i]);
}
handle.Free();
if (H5T.is_variable_str(typeId) > 0)
{
Console.WriteLine("attribute value = {0}", attrStrings[0]);
}
控制台正确输出:
attribute value = bar