1. HDF5简介
Hierarchical Data Format(HDF)是一种针对大量数据进行组织和存储的文件格式。经历了20多年的发展,HDF格式的最新版本是HDF5,它包含了数据模型,库,和文件格式标准。以其便捷有效,移植性强,灵活可扩展的特点受到了广泛的关注和应用。
很多大型机构的数据存储格式都采用了HDF5,比如NASA的地球观测系统,MATLAB的.m文件,流体细算软件CDF,都将HDF5作为标准数据格式。现在HDF5还支持了大数据技术和NoSQL技术,并广泛用于科研,金融,以及其他科学和工程领域。
HDF5在技术上提供了丰富的接口,包含C,C++,Fortran, Python, Java等,能够在不同的语言间完美兼容。
当然批评者也认为HDF5格式具有以下缺点:
1. 设计古老,定制化设置冗长
2. 尽管有150多页的公开标准,但HDF5的非官方实现非常少
3. HDF5没有强制使用UTF8编码,因此客户为了兼容型只好采用ASCII编码
4. 存储的数据不能没有外部工具(如h5repack)的情况下自由的提取和复 制。
2. HDF5在Windows上的安装和使用
我们采用Windows 10 x64操作系统和Visual Studio 2015 x64作为C++编译环境进行说明,如何安装和配置HDF5,并使用HDF5静态和动态库将数据存储为HDF5格式,以及如何查看和读取这些数据。
HDF5软件的安装:
1. 从官方网站下载下载安装包,可以32位和64位都下载安装,安装在不同的文件夹中,如Program Files和Program Files (x86)文件夹下。注意,这里添加的HDF5库的是32位的,该位数应该和要编译的程序的位数相同。
2. 将HDF5安装目录下的bin文件夹地址添加到系统的PATH变量中,用英文分号隔开
Visual Studio 2015中使用HDF5需要进行的配置如下:
1. 打开Project属性页,在[配置属性]->[C/C++]选项卡中,将HDF5安装目录下的include文件夹地址填入附加包含目录项目中
2. 在[配置属性]->[链接器]选项卡中,将HDF5安装目录下的lib文件夹地址填入附加库目录项目中
3. 在[配置属性]->[链接器]->[输入]选项卡中,将链接的库文件添加到附加依赖项中。。这里需要主要,对于动态链接和静态链接添加的库不同
– 动态链接:szip.lib;zlib.lib;hdf5.lib;hdf5_cpp.lib(最后一项针对用C++方法调用HDF5的项目)
– 静态链接:libszip.lib;libzlib.lib;libhdf5.lib;libhdf5_cpp.lib
4. 在[配置属性]->[C/C++]->[代码生成]选项卡中,调整运行库项目。动态链接采用[多线程DLL(/MD)]模式,而静态链接采用[多线程调试DLL(/MDd)]模式。
5. 在采用动态链接时,一定注意最后在[配置属性]->[C/C++]->[预处理器]选项卡中,在预处理器定义项目中定义符号H5_BUILT_AS_DYNAMIC_LIB。否则程序有可能出先000007b错误,或者出现LINK2001无法解析的外部符号_H5T_NATIVE_DOUBLE_g等外部符号无法解析的情况。
至此,我们的Visual Studio环境搭建已经完成,接下来我们开始学习HDF5库使用的学习。
3. HDF5文件结构
3.1 HDF5文件格式
3.2 HDF5结构模型
为了方便数据的组织,HDF5文件通过group的方式组织成树状结构,每个group都是树的节点。
每一个dataset包含两部分的数据,Metadata和Data。其中Metadata包含Data相关的信息,而Data则包含数据本身。
3.3 内置数据类型
C类型 | HDF5内存类型 | HDF5文件类型1 |
---|---|---|
Integer : | ||
int | H5T_NATIVE_INT | H5T_STD_I32BE or H5T_STD_I32LE |
short | H5T_NATIVE_SHORT | H5T_STD_I16BE or H5T_STD_I16LE |
long | H5T_NATIVE_LONG | H5T_STD_I32BE, H5T_STD_I32LE, H5T_STD_I64BE or H5T_STD_I64LE |
long long | H5T_NATIVE_LLONG | H5T_STD_I64BE or H5T_STD_I64LE |
unsigned int | H5T_NATIVE_UINT | H5T_STD_U32BE or H5T_STD_U32LE |
unsigned short | H5T_NATIVE_USHORT | H5T_STD_U16BE or H5T_STD_U16LE |
unsigned long | H5T_NATIVE_ULONG | H5T_STD_U32BE, H5T_STD_U32LE, H5T_STD_U64BE or H5T_STD_U64LE |
unsigned long long | H5T_NATIVE_ULLONG | H5T_STD_U64BE or H5T_STD_U64LE |
Float : | ||
float | H5T_NATIVE_FLOAT | H5T_IEEE_F32BE or H5T_IEEE_F32LE |
double | H5T_NATIVE_DOUBLE | H5T_IEEE_F64BE or H5T_IEEE_F64LE |
3.4 HDF5工具群
h5dump
hDFview
h5cc/h5c++
4. HDF5快速上手全攻略
一般的操作一个HDF5对象的步骤是
1. 打开这个对象;
2. 对这个对象进行操作;
3. 关闭这个对象。
特别要注意的是,一定要在操作结束后关闭对象。因为之前的操作只是生成操作的流程,并不真正执行操作,只有关闭对象操作才会真正出发对对象进行的修改。
4.1 文件(Files)创建/打开/关闭
Python代码
C/C++代码
4.2 群(Group)的建立
Python中将文件树表述成一个dict,keys值是groups成员的名字,values是成员对象(groups或者datasets)本身。文件对象本身作为root group。
Python代码
在C/C++中组的创建使用一个宏H5Gcreate(),这个宏将调用不同版本的组创建函数H5Gcreate1()和H5Gcreate2(),其中1.8.x版本的宏指向H5Gcreate2()。
注意: 在C库中,group只能一层一层创建,子group只有在创建好父group后才能创建,不能一次创建多层group。
C/C++代码
那么对于一个组,我们想知道它是否存在在,应该如何检测呢?如果直接进行读取,那么HDF5会进行报错,所以,我们需要先关闭报错机制,然后进行检验。代码如下
4.3 数据集(Dataset)的创建
H5py中的dataset很类似与Numpy中的array,但支持一些列透明(针对连续存储的选择操作对分块存储同样有效)的存储特性,还支持分块,压缩,和错误校验。
新的数据集可以通过group.create_dateset()或者group.require_dateset()记性创建。已经存在的数据已可以通过群的所以语法进行访问dset = group[“dset_name”]。
python代码
在C/C++语言中,dataspace一共有三种形式
1. H5S_SCALAR: 标量,只有一个元素,rank为0
2. H5S_SIMPLE:正常的数组形式的元素
3. H5S_NULL:没有数据元素
其中最常用的是H5S_SIMPLE类型,它有一个直接的生成函数H5Screate_simple()
其中H5Dwrite()函数匹配内存spaceid和文件spaceid的行为如下,
mem_space_id | file_space_id | Behavior |
---|---|---|
有效id | 有效id | mem_space_id specifies the memory dataspace and the selection within it. file_space_id specifies the selection within the file dataset’s dataspace. |
H5S_ALL | 有效id | The file dataset’s dataspace is used for the memory dataspace and the selection specified with file_space_id specifies the selection within it. The combination of the file dataset’s dataspace and the selection from file_space_id is used for memory also. |
有效id | H5S_ALL | mem_space_id specifies the memory dataspace and the selection within it. The selection within the file dataset’s dataspace is set to the “all” selection. |
H5S_ALL | H5S_ALL | The file dataset’s dataspace is used for the memory dataspace and the selection within the memory dataspace is set to the “all” selection. The selection within the file dataset’s dataspace is set to the “all” selection. |
写入程序
读出程序
和numpy一样,len()函数返回dataset中第一个轴的长度。但是如果在32位平台上第一个轴长度超过2^32时len(dataset)将失效,因此推荐使用dataset.len()方法。
4.4.2 C/C++部分
在C语言中,访问原数据集子集的关键在于构造内存的dataspace,通过内存和文件中dataspace的配合实现访问选择子集的效果。在HDF5中,有两种选择,元素(element)选择和超块(hyperslab)选择,分别通过函数H5Sselect_elements()和H5Sselect_hyperslab()两个函数实现。这两个函数都会修改传入dataspace_id对应的dataspace空间性质,以此实现选择的子集。
和MPI的子集选择方法相同,HDF5的子集选择定义子集四大件:
– offset: 位置补偿
– stride: 间隙
– count: 块数
– block: 块大小
例如想要从一个(8,10)的dataspace中选择一个如图(7,4)的dataspace,需要定义的四大件如下。
C/C++代码
4.5 添加注释——创建属性(Attribute)
属性是一种dataset的元数据(metadata),它描述了数据的相关信息,可以把属性理解成注释,所有的group和datasets都支持属性。
h5py采用dataset.attrs方法访问属性,比如
C/C++代码
<br />
4.6 数据压缩(Compression)
HDF5的数据集默认是连续空间存储的。单可以通过设置让HDF5吧数据进行分块(chunked)存储,也就是说将数据分割为固定大小的小块分开存储,再通过B-Tree进行索引。
分块存储的方式是的数据集可以改变大小,也可以进行压缩过滤。
块的分割大小大概在10KiB到1MiB之间,数据集越大,则块也相应越多。分块以后数据读取将整块郑块的进行,如果对分块干到困惑,python中允许可以直接使用h5py的自动大小(chunks=True)
有了分块的数据集,就可以对数据集进行压缩了,通过无损的压缩过滤器可以将数据集进行无损失的压缩,利用函数group.create_dateset(compression=”filter”)。
常见的无损压缩过滤器有
– GZIP过滤器(“gzip”): 每个HDF5的标配,中等速度高压缩率,具有参数compression_opts取值从0到9控制压缩等级,默认值为4
– LZF过滤器(“lzf”): 快速但压缩率中等的压缩器
– SZIP过滤器(“szip”): NASA开发的专利保护压缩器
在C++中,分块和压缩性质都是dataset创建性质列表中的内容,通过下面的步骤就可以方便的创建数据集的压缩性质
1. 创建数据集创建性质列表
2. 在性质列表中设置分块性质
3. 在相纸列表中添加压缩过滤器
之后数据集的读写就如同正常的数据集了。演示代码如下
C/C++代码
5. 总结
注意文件类型是由编译器和系统环境决定的,比如我用的Windows 10和Visual Studio 2015编译器double类型对应的HDF5文件类型是H5T_IEEE_F64LE。