H5G
、H5L
、H5O
是 HDF5 C API 的分组接口,在 HDF.PInvoke.NETStandard
(C# 的 HDF5 封装包)里,它们分别代表 HDF5 底层 对象层(Object layer)、组层(Group layer) 和 链接层(Link layer) 的操作模块。
🧱 一、背景概念
在 HDF5 中,一切数据(datasets、groups、attributes)都组织在一个层次结构里,像文件系统:
/ <-- 根组/GroupA/Dataset1/SubGroup/Dataset2
HDF5 的 API 是分模块设计的,C 层 API 对应多个模块,比如:
模块名 | 功能说明 | 常见函数前缀 |
---|---|---|
H5F | 文件(File)管理 | H5F.create , H5F.open , H5F.close |
H5G | 组(Group)管理 | H5G.create , H5G.open , H5G.get_info |
H5D | 数据集(Dataset)管理 | H5D.create , H5D.write , H5D.read |
H5S | 数据空间(Dataspace)定义 | H5S.create_simple |
H5T | 数据类型(Datatype)定义 | H5T.copy , H5T.commit |
H5A | 属性(Attribute)操作 | H5A.create , H5A.read |
H5L | 链接(Link)管理 | H5L.create_hard , H5L.create_soft , H5L.exists |
H5O | 对象(Object)管理 | H5O.open , H5O.get_info , H5O.copy |
🧩 二、 H5G
、H5L
、H5O
这三个模块
🧠 1. H5G
—— Group(组)操作
代表 HDF5 层次结构中的“文件夹”。
常见用途:
- 创建 / 打开 / 关闭组
- 获取组信息(比如子对象数量)
常见函数:
long gid = H5G.create(fileId, "GroupA");
H5G.close(gid);
组是存放数据集和子组的容器。
🔗 2. H5L
—— Link(链接)操作
HDF5 中的“链接”相当于文件系统里的“路径项”或“符号链接”。
每个对象(Group / Dataset)都通过“链接”挂在某个组下面。
主要作用:
- 创建硬链接(hard link)或软链接(soft link)
- 检查、移动、删除链接
- 查询链接是否存在
常见函数:
H5L.create_hard(sourceLocId, "GroupA/Dataset1", destLocId, "CopiedDataset");
bool exists = H5L.exists(fileId, "GroupA/Dataset1") > 0;
区别:
- 硬链接:多个路径指向同一个对象(类似 Linux 硬链接)
- 软链接:路径字符串引用(类似符号链接)
🧩 3. H5O
—— Object(对象)操作
HDF5 文件中所有可命名的东西(Group、Dataset、Datatype)都是 对象 (Object)。
H5O
模块就是操作这些对象的通用接口。
主要用途:
- 打开对象(不用区分是组还是数据集)
- 获取对象信息(类型、创建时间、引用次数等)
- 拷贝对象(整个数据集或组)
- 检查对象是否存在
常见函数:
long oid = H5O.open(fileId, "GroupA/Dataset1");
H5O.info_t info = new H5O.info_t();
H5O.get_info(oid, ref info);
H5O.close(oid);
⚙️ 三、它们之间的关系
可以这么理解:
层次 | 模块 | 比喻(文件系统类比) |
---|---|---|
文件 | H5F |
打开/关闭文件 |
组 | H5G |
文件夹操作 |
链接 | H5L |
文件系统中的路径项 / 软硬链接 |
对象 | H5O |
一切可被命名的对象(文件或文件夹) |
它们是互相关联的:
H5G
管理组本身H5L
管理路径和命名H5O
管理底层对象元信息
🧪 四、举个例子
比如我们想复制一个数据集:
// 等价于 shell 命令: cp /GroupA/Dataset1 /GroupB/DatasetCopy
H5O.copy(fileId, "/GroupA/Dataset1", fileId, "/GroupB/DatasetCopy", 0, 0);
内部其实涉及:
H5L
查找/GroupA/Dataset1
这个路径对应的链接;H5O
拿到实际对象;H5G
用于定位组/GroupB
。
✅ 小结
模块 | 作用 | 常用函数 |
---|---|---|
H5G |
操作组(Group) | create , open , get_info , close |
H5L |
操作链接(路径、软硬链接) | create_hard , create_soft , exists , delete |
H5O |
操作通用对象(Group / Dataset / Type) | open , get_info , copy , close |
下面是一个 完整的示例 C# 程序:
用 HDF.PInvoke
创建一个文件 → 新建组 /GroupA
→ 在里面新建一个数据集 → 用 H5O.copy
复制它 → 用 H5L.exists
验证链接存在。
非常好 👍
下面是一个完整的、可以直接运行的 C# 示例程序,使用 NuGet 包
HDF.PInvoke.NETStandard (v1.10.502)
它演示了:
- 创建 HDF5 文件
- 创建组(
H5G
) - 创建数据集(
H5D
) - 复制对象(
H5O.copy
) - 检查链接是否存在(
H5L.exists
) - 最后关闭所有资源
并附带详细中文注释,帮助我们理解 HDF5 各层的作用。
✅ 完整代码示例(可运行)
using System;
using HDF.PInvoke;
using System.Runtime.InteropServices;class Program
{static void Main(){const string fileName = "example.h5";//=====================================================// 一、创建一个新的 HDF5 文件//=====================================================// H5F_ACC_TRUNC 表示如果文件存在则覆盖long fileId = H5F.create(fileName, H5F.ACC_TRUNC);Console.WriteLine($"✅ 创建文件: {fileName}, fileId = {fileId}");//=====================================================// 二、在根目录下创建一个组 /GroupA//=====================================================long groupId = H5G.create(fileId, "/GroupA");Console.WriteLine("✅ 创建组: /GroupA");//=====================================================// 三、在 /GroupA 下创建一个简单的数据集 /GroupA/Dataset1//=====================================================// 定义一个简单的 1D 空间,长度为 5ulong[] dims = { 5 };long spaceId = H5S.create_simple(1, dims, null);// 数据类型:float (32位)long typeId = H5T.copy(H5T.NATIVE_FLOAT);// 创建数据集long datasetId = H5D.create(groupId, "Dataset1", typeId, spaceId);Console.WriteLine("✅ 创建数据集: /GroupA/Dataset1");// 写入一些测试数据float[] data = { 1.1f, 2.2f, 3.3f, 4.4f, 5.5f };GCHandle hnd = GCHandle.Alloc(data, GCHandleType.Pinned);H5D.write(datasetId, H5T.NATIVE_FLOAT, H5S.ALL, H5S.ALL, H5P.DEFAULT, hnd.AddrOfPinnedObject());hnd.Free();Console.WriteLine("✅ 写入数据完成");// 关闭数据集和空间H5D.close(datasetId);H5S.close(spaceId);H5T.close(typeId);H5G.close(groupId);//=====================================================// 四、创建另一个组 /GroupB//=====================================================long groupBId = H5G.create(fileId, "/GroupB");H5G.close(groupBId);Console.WriteLine("✅ 创建组: /GroupB");//=====================================================// 五、使用 H5O.copy() 将 Dataset1 从 GroupA 复制到 GroupB//=====================================================// 语法: H5O.copy(src_loc, src_name, dst_loc, dst_name, cpypl_id, lcpl_id)// 参数解释:// src_loc: 源所在的文件或组 ID// src_name: 源路径// dst_loc: 目标文件或组 ID// dst_name: 新对象路径// cpypl_id: 拷贝属性列表(默认 0)// lcpl_id: 链接创建属性列表(默认 0)H5O.copy(fileId, "/GroupA/Dataset1", fileId, "/GroupB/DatasetCopy", 0, 0);Console.WriteLine("✅ 复制对象: /GroupA/Dataset1 → /GroupB/DatasetCopy");//=====================================================// 六、使用 H5L.exists() 检查新链接是否存在//=====================================================bool exists = H5L.exists(fileId, "/GroupB/DatasetCopy") > 0;Console.WriteLine($"🔍 链接 /GroupB/DatasetCopy 是否存在: {exists}");//=====================================================// 七、用 H5O.open() 打开复制后的对象,并读取信息//=====================================================long objId = H5O.open(fileId, "/GroupB/DatasetCopy");H5O.info_t info = new H5O.info_t();H5O.get_info(objId, ref info);Console.WriteLine($"ℹ️ 对象类型: {info.type}"); // H5O.type_t.DATASETH5O.close(objId);//=====================================================// 八、关闭文件//=====================================================H5F.close(fileId);Console.WriteLine("✅ 文件已关闭");}
}
🧭 运行后输出示例
✅ 创建文件: example.h5, fileId = 72057594037927936
✅ 创建组: /GroupA
✅ 创建数据集: /GroupA/Dataset1
✅ 写入数据完成
✅ 创建组: /GroupB
✅ 复制对象: /GroupA/Dataset1 → /GroupB/DatasetCopy
🔍 链接 /GroupB/DatasetCopy 是否存在: True
ℹ️ 对象类型: H5O_TYPE_DATASET
✅ 文件已关闭
运行结束后,得到一个结构如下的 HDF5 文件:
/
├── GroupA
│ └── Dataset1
└── GroupB└── DatasetCopy
💡 总结要点
模块 | 功能 | 示例 |
---|---|---|
H5G |
操作组(Group) | 创建 /GroupA , /GroupB |
H5D |
操作数据集(Dataset) | 创建并写入 Dataset1 |
H5O |
操作对象(Object) | 复制整个对象,查询信息 |
H5L |
操作链接(Link) | 检查路径是否存在 |