本文从本人简书博客同步过来
在上一篇中我们介绍了 caput 中另一个模块 miarray 提供的建立在 numpy array 基础上的并行分布式数组 MPIArray,其中也提到了 HDF5 文件及其操作,我们将在后面介绍并行分布式的 HDF5 相关操作,在此之前我们先介绍 HDF5 文件的基本内容以及 Python 中操作 HDF5 文件的方法,以为后面的介绍作铺垫,下面我们介绍 HDF5 文件以及操作 HDF5 文件的 Python 工具 h5py。
HDF(Hierarchical Data Format)指一种为存储和处理大容量科学数据设计的文件格式及相应库文件。HDF 最早由美国国家超级计算应用中心 NCSA 开发,目前在非盈利组织 HDF 小组维护下继续发展。当前流行的版本是 HDF5。HDF5 拥有一系列的优异特性,使其特别适合进行大量科学数据的存储和操作,如它支持非常多的数据类型,灵活,通用,跨平台,可扩展,高效的 I/O 性能,支持几乎无限量(高达 EB)的单文件存储等,详见其官方介绍:https://support.hdfgroup.org/HDF5/ 。
Python 中有一系列的工具可以操作和使用 HDF5 数据,其中最常用的是 h5py 和 PyTables。我们只介绍 h5py。
一个 HDF5 文件是存储两类对象的容器,这两类对象分别为:
一个 HDF5 文件从一个命名为 “/” 的 group 开始,所有的 dataset 和其它 group 都包含在此 group 下,当操作 HDF5 文件时,如果没有显式指定 group 的 dataset 都是默认指 “/” 下的 dataset,另外类似相对文件路径的 group 名字都是相对于 “/” 的。
HDF5 文件的 dataset 和 group 都可以拥有描述性的元数据,称作 attribute。
用 h5py 操作 HDF5 文件,我们可以像使用目录一样使用 group,像使用 numpy 数组一样使用 dataset,像使用字典一样使用属性,非常方便和易用。
如果仅仅想简单的使用 h5py 来操作 HDF5(无并行支持和其它定制特性),安装 h5py 是非常简单的,可以使用 conda 或者 pip 直接安装:
$ conda install h5py
或者
$ pip install h5py
在后面我们将会介绍结合 mi4py 和 h5py 进行并行的HDF5 操作,因此下面介绍如何编译和安装支持并行操作的 HDF5 库和 h5py 软件包。
从 https://support.hdfgroup.org/downloads/index.html 下载 HDF5 软件,解压后进入顶层目录。编译并行 HDF5 需要用到一个支持并行的编译器,如 mpicc (安装了 OpenMP 或 MPICH 后都有),通过在终端中输入
$ which mpicc
得到 mpicc 的路径,然后按照下列步骤进行编译和安装:
$ CC=/path/to/your/mpicc ./configure --enable-parallel --enable-shared --prefix=
$ make # build the library
$ make check # verify the correctness
$ make install
安装完并行的 HDF5 后,从 https://pypi.org/project/h5py/#files 下载 h5py 安装包并解压,在其顶层目录执行以下命令编译和安装:
$ export CC=mpicc
$ python setup.py configure --mpi [--hdf5=/path/to/parallel/hdf5]
$ python setup.py build
$ python setup.py install
下面我们只简要介绍 h5py 的基本操作,并行的 h5py 操作会在下一篇中介绍。更详细的内容可参考 h5py 的文档。
class File(name, mode=None, driver=None, libver=None, userblock_size=None, **kwds)
打开或创建一个 HDF5 文件,name
为文件名字符串,mode
为打开文件的模式,driver
可以指定一种驱动方式,如需进行并行 HDF5 操作,可设置为 ‘mpio’,libver
可以指定使用的兼容版本,默认为 ‘earliest’,也可以指定为 ‘latest’,userblock_size
以字节为单位指定一个在文件开头称作 user block 的数据块,一般不需要设置。返回所打开文件的句柄。
有效的 mode
参数有:
mode | 说明 |
---|---|
r | 只读,文件必须存在 |
r+ | 读写,文件必须存在 |
w | 创建新文件写,已经存在的文件会被覆盖掉 |
w- / x | 创建新文件写,文件如果已经存在则出错 |
a | 打开已经存在的文件进行读写,如果不存在则创建一个新文件读写,此为默认的 mode |
create_group(self, name, track_order=False)
创建一个新的 group。以类似目录路径的形式指明所创建 group 的名字 name
,如果 track_order
为 True,则会跟踪在当前 group 下的 group 和 dataset 创建的先后顺序。该方法可以在打开的文件句柄(相当于 “/” group)或者一个存在的 group 对象上调用,此时 name
的相对路径就是相对于此 group 的。
create_dataset(self, name, shape=None, dtype=None, data=None, **kwds)
创建一个新的 dataset。以类似文件路径的形式指明所创建 dataset 的名字 name
,shape
以一个 tuple 或 list 的形式指明创建 dataset 的 shape,用 “()” 指明标量数据的 shape,dtype
指明所创建 dataset 的数据类型,可以为 numpy dtype 或者一个表明数据类型的字符串,data
指明存储到所创建的 dataset 中的数据。如果 data
为 None,则会创建一个空的 dataset,此时 shape
和 dtype
必须设置;如果 data
不为 None,则 shape
和 dtype
可以不设置而使用 data
的 shape 和 dtype,但是如果设置的话,必须与 data
的 shape 和 dtype 兼容。
打开的文件句柄(相当于 “/” group),group 和 dataset 上都可以创建 attribute,以类似于字典的操作方式创建和读取 attribute。
下面给出 h5py 的简单使用例程。
# h5py_demo.py
"""
Demonstrates how to use h5py.
Run this like:
$ python h5py_demo.py
"""
import os
import numpy as np
import h5py
file_name = 'test.hdf5'
# create a new HDF5 file
f = h5py.File(file_name)
# create a new group
f.create_group('/grp1') # or f.create_group('grp1')
# create a nother group inside grp1
f.create_group('/grp1/grp2') # or f.create_group('grp1/grp2')
# create a dataset in group "/"
data = np.arange(6).reshape(2, 3)
f.create_dataset('dset1', data=data) # or f.create_dataset('/dset1', data=data)
# create another dataset in group /grp1
f.create_dataset('grp1/dset2', data=data) # or f.create_dataset('/grp1/dset2', data=data)
# create an attribute of "/"
f.attrs['a'] = 1 # or f.attrs['/a'] = 1
# create an attribute of group "/grp1"
f['grp1'].attrs['b'] = 'xyz'
# create an attribute of dataset "/grp1/dset2"
f['grp1/dset2'].attrs['c'] = np.array([1, 2])
# close file
f.close()
# open the existing test.hdf5 for read only
f = h5py.File(file_name, 'r')
# read dataset /dset1
print '/dset1 = %s' % f['dset1'][:]
# read dataset /grp1/dset2
print '/grp1/dset2 = %s' % f['/grp1/dset2'][:]
# get attributes
print f.attrs['a']
print f['grp1'].attrs['b']
print f['grp1/dset2'].attrs['c']
# remove the created file
os.remove(file_name)
运行结果如下:
$ python h5py_demo.py
/dset1 = [[0 1 2]
[3 4 5]]
/grp1/dset2 = [[0 1 2]
[3 4 5]]
1
xyz
[1 2]
以上我们简要介绍了 HDF5 和 h5py 的基本操作,在下一篇中我们将介绍利用 mpi4py 和 h5py 进行并行分布式的 HDF5 操作。