查看: 145|回复: 3

Python中使用h5py操作HDF5文件:写入、读取、压缩与扩展详解

[复制链接]
发表于 3 小时前 | 显示全部楼层 |阅读模式
HDF5(Hierarchical Data Format version 5)是一种专为存储和管理大规模、复杂数据设计的高性能文件格式。在Python生态中,h5py是最主流、最稳定的操作库,它将HDF5的Group映射为字典、Dataset映射为NumPy数组,支持切片和延迟加载,特别适合科学计算和机器学习场景。本文基于实际代码,系统讲解h5py的核心用法,包括创建/读取数据集、组织层级、压缩存储、动态扩容以及遍历结构等关键操作。
  1. pip install h5py
复制代码
或使用conda:
  1. conda install h5py
复制代码

一、基础写入操作

使用with语句管理文件生命周期,避免资源泄漏。

1. 创建Dataset
  1. import h5py
  2. import numpy as np
  3. with h5py.File("data_example.h5", "w") as f:
  4.     # 方式A:直接写入已有数组
  5.     matrix_data = np.random.randn(100, 100)
  6.     f.create_dataset("matrix", data=matrix_data)
  7.     # 方式B:先指定shape和dtype,再填充
  8.     ds = f.create_dataset("empty_matrix", shape=(10, 10), dtype="float32")
  9.     ds[...] = 1.0
复制代码

2. 创建Group(文件夹)
  1. with h5py.File("data_example.h5", "w") as f:
  2.     group_sensor = f.create_group("sensor_data")
  3.     group_gps = group_sensor.create_group("gps")
  4.     gps_coords = np.array([[39.9, 116.4], [31.2, 121.5]])
  5.     group_gps.create_dataset("coordinates", data=gps_coords)
  6.     # 隐式创建层级(自动生成缺失的组)
  7.     f.create_dataset("sensor_data/temperature/reading", data=np.array([22.5, 23.0, 22.8]))
复制代码

3. 写入Attribute(元数据)
  1. with h5py.File("data_example.h5", "w") as f:
  2.     ds = f.create_dataset("temperature", data=[22.5, 23.0, 22.8])
  3.     ds.attrs["unit"] = "Celsius"
  4.     ds.attrs["sensor_model"] = "DHT22"
  5.     ds.attrs["calibration_factor"] = 1.02
  6.     f.attrs["author"] = "Antigravity AI"
复制代码

4. 可扩展数据集(动态追加)

通过maxshape参数指定每个维度的最大长度,None表示无限。
  1. with h5py.File('resizable.h5', 'w') as f:
  2.     dset = f.create_dataset('expandable',
  3.                             shape=(100,),
  4.                             maxshape=(None,),
  5.                             dtype='float64')
  6.     dset[:] = np.arange(100)
  7.     # 扩展后追加
  8.     dset.resize((200,))
  9.     dset[100:] = np.arange(100, 200)
  10.     # 二维可扩展(仅第一维可扩展)
  11.     dset2 = f.create_dataset('expandable_2d',
  12.                              shape=(10, 20),
  13.                              maxshape=(None, 20),
  14.                              dtype='int32')
  15.     dset2[:] = np.arange(200).reshape(10, 20)
  16.     dset2.resize((15, 20))
  17.     dset2[10:] = np.arange(200, 300).reshape(5, 20)
复制代码

5. 压缩存储与分块(Chunks)

启用压缩时,必须同时指定chunks参数。压缩能大幅节省磁盘空间,但会略微增加读取时的CPU开销。常见压缩器为gzip,压缩等级1-9,默认等级4。
  1. with h5py.File("compressed_example.h5", "w") as f:
  2.     large_data = np.random.randn(1000, 1000)
  3.     f.create_dataset(
  4.         "compressed_matrix",
  5.         data=large_data,
  6.         compression="gzip",
  7.         compression_opts=4,
  8.         chunks=(100, 100)
  9.     )
复制代码

为什么压缩必须配合分块?

原理上,如果不分块,HDF5采用连续存储,即整个数据集在磁盘上是一块连续二进制流。压缩后,数据变成变长字节,导致:
1. 无法通过公式直接计算某个元素的磁盘偏移,必须解压整个文件才能读取一小块数据;
2. 局部修改会导致文件整体重写(因为压缩后字节数变化)。

分块将多维数组切分为大小相同的子块,每个子块独立压缩并单独存储在磁盘上,通过B树索引管理。这样:
- 读取某个元素时,只需解压包含该元素的块,性能大幅提升;
- 修改某块数据只影响该块的物理位置,无需移动其他块;
- 支持动态扩容,新块直接追加到磁盘空白处。

6. 保存字符串

HDF5原生不支持Python的可变长Unicode字符串。推荐使用h5py.string_dtype()指定UTF-8编码,并配合asstr()读取。
  1. with h5py.File("strings_example.h5", "w") as f:
  2.     utf8_type = h5py.string_dtype(encoding="utf-8")
  3.     words = np.array(["你好", "HDF5", "Python 数据科学"], dtype=object)
  4.     ds = f.create_dataset("chinese_words", (3,), dtype=utf8_type)
  5.     ds[:] = words
  6.     # 简写方式:直接存储字节串
  7.     f.create_dataset("ascii_bytes", data=[b"hello", b"world"])
复制代码

二、读取HDF5文件

1. 递归遍历文件结构

使用visititems()方法,结合自定义回调函数,可打印出完整的树形结构及属性。
  1. def print_structure(name, obj):
  2.     indent = " " * name.count("/")
  3.     if isinstance(obj, h5py.Dataset):
  4.         print(f"{indent}Dataset: {name} (shape={obj.shape}, dtype={obj.dtype})")
  5.         if len(obj.attrs) > 0:
  6.             for k, v in obj.attrs.items():
  7.                 print(f"{indent}  Attribute {k}: {v}")
  8.     elif isinstance(obj, h5py.Group):
  9.         print(f"{indent}Group: {name}")
  10. with h5py.File("data_example.h5", "r") as f:
  11.     print("--- 文件树形结构 ---")
  12.     f.visititems(print_structure)
复制代码

2. 读取全部数据

当数据集内存可容纳时,直接使用切片[:]即可获得完整NumPy数组。
  1. with h5py.File("data_example.h5", "r") as f:
  2.     if "matrix" in f:
  3.         data = f["matrix"][:]
  4.         print("数据类型:", type(data))
  5.         print("数据形状:", data.shape)
复制代码

3. 切片与延迟加载(核心优势)

获取数据集对象后,并不立即加载数据。只有在执行切片操作时才触发实际I/O,可高效处理数GB大文件。
  1. with h5py.File("data_example.h5", "r") as f:
  2.     dataset = f["matrix"]  # 仅获取引用,未读取
  3.     sub_data = dataset[0:10, 0:5]  # 仅加载局部
  4.     print("局部数据形状:", sub_data.shape)
复制代码

三、常用操作速查表
打开文件(读):f = h5py.File('data.h5', 'r')  (推荐用with)
打开文件(写,覆盖):f = h5py.File('data.h5', 'w')
打开文件(追加):f = h5py.File('data.h5', 'a')
创建Group:g = f.create_group('grp')
判断路径是否存在:'grp/dset' in f
删除节点:del f['grp/dset']
创建Dataset:f.create_dataset('ds', data=arr)
创建空Dataset:f.create_dataset('ds', shape=(100,), dtype='i')
启用压缩:f.create_dataset('ds', data=arr, compression='gzip')
创建可扩展Dataset:f.create_dataset('ds', shape=(0,10), maxshape=(None,10))
改变大小:dset.resize((new_size, 10))
写入属性:obj.attrs['key'] = value
读取属性:value = obj.attrs['key']
遍历结构:f.visititems(callback)
读取完整数据:arr = f['ds'][:]
切片读取:arr = f['ds'][0:10,2:5]
字符串解码:s = f['str_ds'].asstr()[0]

通过以上代码和说明,你可以快速上手h5py,高效管理HDF5格式的科学数据。实际项目中,请根据数据大小和访问模式合理选择压缩与分块策略,以在磁盘空间和读写性能之间取得平衡。
回复

使用道具 举报

发表于 3 小时前 | 显示全部楼层

Re: Python中使用h5py操作HDF5文件:写入、读取、压缩与扩展详解

感谢楼主的详细教程,写得非常清晰!特别是对压缩必须配合分块的原因解释得很透彻,以前只是照用,现在终于明白原理了。可扩展数据集的用法也很实用,收藏准备实践一下。期待后续关于字符串保存的部分~
回复 支持 反对

使用道具 举报

发表于 3 小时前 | 显示全部楼层

Re: Python中使用h5py操作HDF5文件:写入、读取、压缩与扩展详解

很详尽的教程,特别是压缩和分块的原理部分讲得很透彻,之前一直没理解为什么压缩必须配合chunks,现在明白了。另外动态扩容的例子也很实用,正好在项目里需要随时追加数据。不过字符串保存那块好像被截断了,方便补全一下吗?期待后续内容!
回复 支持 反对

使用道具 举报

发表于 3 小时前 | 显示全部楼层

Re: Python中使用h5py操作HDF5文件:写入、读取、压缩与扩展详解

谢谢楼主分享,讲得非常清楚!特别是压缩必须配合分块的那段原理,之前一直没搞懂,看完才明白连续存储为啥不能直接压缩。想问下,如果我用可扩展数据集频繁往里追加数据,重复resize会不会导致文件碎片化严重?h5py内部有没有类似内存整理之类的机制?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-6-25 15:41 , Processed in 0.033872 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部