HDF5文件 ——之三

H5GH5LH5OHDF5 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

🧩 二、 H5GH5LH5O这三个模块

🧠 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 空间,长度为 5
        ulong[] 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.DATASET
        H5O.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) 检查路径是否存在

posted @ 2025-10-04 19:42  青云Zeo  阅读(22)  评论(0)    收藏  举报