https://zhuanlan.zhihu.com/p/104145585

HDF5 结构

HDF5 文件一般以 .h5 或者 .hdf5 作为后缀名,需要专门的软件才能打开预览文件的内容。HDF5 文件结构中有 2 primary objects: GroupsDatasets

  • Groups 就类似于文件夹,每个 HDF5 文件其实就是根目录 (root) group'/'
  • Datasets 类似于 NumPy 中的数组 array 。

每个 dataset 可以分成两部分: 原始数据 (raw) data values元数据 metadata (a set of data that describes and gives information about other data => raw data)。

  1. +-- Dataset
  2. | +-- (Raw) Data Values (eg: a 4 x 5 x 6 matrix)
  3. | +-- Metadata
  4. | | +-- Dataspace (eg: Rank = 3, Dimensions = {4, 5, 6})
  5. | | +-- Datatype (eg: Integer)
  6. | | +-- Properties (eg: Chuncked, Compressed)
  7. | | +-- Attributes (eg: attr1 = 32.4, attr2 = "hello", ...)
  8. |

从上面的结构中可以看出:

  • Dataspace 给出原始数据的 (Rank) 和维度 (dimension)
  • Datatype 给出数据类型
  • Properties 说明该 dataset 的分块储存以及压缩情况
    • Chunked: Better access time for subsets; extendible
    • Chunked & Compressed: Improves storage efficiency, transmission speed
  • Attributes 为该 dataset 的其他自定义属性

整个 HDF5 文件的结构如下所示:

  1. +-- /
  2. | +-- group_1
  3. | | +-- dataset_1_1
  4. | | | +-- attribute_1_1_1
  5. | | | +-- attribute_1_1_2
  6. | | | +-- ...
  7. | | |
  8. | | +-- dataset_1_2
  9. | | | +-- attribute_1_2_1
  10. | | | +-- attribute_1_2_2
  11. | | | +-- ...
  12. | | |
  13. | | +-- ...
  14. | |
  15. | +-- group_2
  16. | | +-- dataset_2_1
  17. | | | +-- attribute_2_1_1
  18. | | | +-- attribute_2_1_2
  19. | | | +-- ...
  20. | | |
  21. | | +-- dataset_2_2
  22. | | | +-- attribute_2_2_1
  23. | | | +-- attribute_2_2_2
  24. | | | +-- ...
  25. | | |
  26. | | +-- ...
  27. | |
  28. | +-- ...
  29. |

HDF5 下载与安装(略)

  • 注意: 当为 python 安装 HDF5h5py 库时,使用 conda install h5py 或者 pip install h5py 后也会安装部分二进制文件 (如 h5dump, h5cc/h5c++, h5fc 等) 和库文件,但是可能不完整,导致 HDF5 的 C/C++ 编译器 h5cc/h5c++ 和 Fortran 编译器 h5fc 无法正常工作。
  • 解决办法: h5c++ 无法正常编译 C++ 文件,终端输入 which h5c++, 若显示该二进制文件在 python 的二进制 (binary) 文件夹 bin 内,则只需找到 brew 或者其他安装包管理工具下载的 h5c++ (一般在 /usr/local/bin 内) 或者官网下载解压后的 h5c++,在根目录 (~) 下的 .bashrc 文件 (或者其他 shell, 如 zsh 的配置文件 .zshrc) 内添加 alias h5c++ = /usr/local/bin/h5c++ 就可以了。

若是想用 clang++ 或者 g++ 而非 h5c++ 编译, 其中只要添加一些头文件 (-I) 和库文件 (-L) 的 flags 就行了。首先确认 h5c++ 可以正常编译后,在终端输入 h5c++ -show, 会显示 CXX_COMPILER + CXX_FLAGS, 例如: g++ -I/usr/local/opt/szip/include -L/usr/local/Cellar/hdf5/1.10.6/lib /usr/local/Cellar/hdf5/1.10.6/lib/libhdf5_hl_cpp.a /usr/local/Cellar/hdf5/1.10.6/lib/libhdf5_cpp.a /usr/local/Cellar/hdf5/1.10.6/lib/libhdf5_hl.a /usr/local/Cellar/hdf5/1.10.6/lib/libhdf5.a -L/usr/local/opt/szip/lib -lsz -lz -ldl -lm , 故我们可以使用 CXX_COMPILER + XXX.cpp + CXX_FLAGS 来编译 C++ 文件 (因为编译依赖关系,CXX_FLAGS 通常放在最后,XXX.cpp 放在 CXX_FLAGS 之前,否则可能会无法成功编译) 。

Python 读写 HDF5 文件

HDF5pythonh5py 调用起来比较简单,我在这给出一个简单的例子:
/h5py_example.py

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3. #
  4. # Created by WW on Jan. 26, 2020
  5. # All rights reserved.
  6. #
  7. import h5py
  8. import numpy as np
  9. def main():
  10. #===========================================================================
  11. # Create a HDF5 file.
  12. f = h5py.File("h5py_example.hdf5", "w") # mode = {'w', 'r', 'a'}
  13. # Create two groups under root '/'.
  14. g1 = f.create_group("bar1")
  15. g2 = f.create_group("bar2")
  16. # Create a dataset under root '/'.
  17. d = f.create_dataset("dset", data=np.arange(16).reshape([4, 4]))
  18. # Add two attributes to dataset 'dset'
  19. d.attrs["myAttr1"] = [100, 200]
  20. d.attrs["myAttr2"] = "Hello, world!"
  21. # Create a group and a dataset under group "bar1".
  22. c1 = g1.create_group("car1")
  23. d1 = g1.create_dataset("dset1", data=np.arange(10))
  24. # Create a group and a dataset under group "bar2".
  25. c2 = g2.create_group("car2")
  26. d2 = g2.create_dataset("dset2", data=np.arange(10))
  27. # Save and exit the file.
  28. f.close()
  29. ''' h5py_example.hdf5 file structure
  30. +-- '/'
  31. | +-- group "bar1"
  32. | | +-- group "car1"
  33. | | | +-- None
  34. | | |
  35. | | +-- dataset "dset1"
  36. | |
  37. | +-- group "bar2"
  38. | | +-- group "car2"
  39. | | | +-- None
  40. | | |
  41. | | +-- dataset "dset2"
  42. | |
  43. | +-- dataset "dset"
  44. | | +-- attribute "myAttr1"
  45. | | +-- attribute "myAttr2"
  46. | |
  47. |
  48. '''
  49. #===========================================================================
  50. # Read HDF5 file.
  51. f = h5py.File("h5py_example.hdf5", "r") # mode = {'w', 'r', 'a'}
  52. # Print the keys of groups and datasets under '/'.
  53. print(f.filename, ":")
  54. print([key for key in f.keys()], "\n")
  55. #===================================================
  56. # Read dataset 'dset' under '/'.
  57. d = f["dset"]
  58. # Print the data of 'dset'.
  59. print(d.name, ":")
  60. print(d[:])
  61. # Print the attributes of dataset 'dset'.
  62. for key in d.attrs.keys():
  63. print(key, ":", d.attrs[key])
  64. print()
  65. #===================================================
  66. # Read group 'bar1'.
  67. g = f["bar1"]
  68. # Print the keys of groups and datasets under group 'bar1'.
  69. print([key for key in g.keys()])
  70. # Three methods to print the data of 'dset1'.
  71. print(f["/bar1/dset1"][:]) # 1. absolute path
  72. print(f["bar1"]["dset1"][:]) # 2. relative path: file[][]
  73. print(g['dset1'][:]) # 3. relative path: group[]
  74. # Delete a database.
  75. # Notice: the mode should be 'a' when you read a file.
  76. '''
  77. del g["dset1"]
  78. '''
  79. # Save and exit the file
  80. f.close()
  81. if __name__ == "__main__":
  82. main()