如何用Rust的hdf5-rust crate读取HDF5数据集的字符串属性?
问题描述
HDF5文件结构
通过h5dump查看的文件结构如下:
❯ h5dump -n GMTCO_npp_d20181005_t2022358_e2024003_b35959_c20181008035331888329_cspp_dev.h5 HDF5 "GMTCO_npp_d20181005_t2022358_e2024003_b35959_c20181008035331888329_cspp_dev.h5" { FILE_CONTENTS { group / group /All_Data group /All_Data/VIIRS-MOD-GEO-TC_All dataset /All_Data/VIIRS-MOD-GEO-TC_All/Height dataset /All_Data/VIIRS-MOD-GEO-TC_All/Latitude dataset /All_Data/VIIRS-MOD-GEO-TC_All/Longitude ... group /Data_Products group /Data_Products/VIIRS-MOD-GEO-TC dataset /Data_Products/VIIRS-MOD-GEO-TC/VIIRS-MOD-GEO-TC_Aggr dataset /Data_Products/VIIRS-MOD-GEO-TC/VIIRS-MOD-GEO-TC_Gran_0 } }
目标属性信息
需要读取数据集/Data_Products/VIIRS-MOD-GEO-TC/VIIRS-MOD-GEO-TC_Gran_0的字符串属性N_Granule_ID,其元数据如下:
ATTRIBUTE "N_Granule_ID" { DATATYPE H5T_STRING { STRSIZE 16; STRPAD H5T_STR_NULLTERM; CSET H5T_CSET_ASCII; CTYPE H5T_C_S1; } DATASPACE SIMPLE { ( 1, 1 ) / ( 1, 1 ) } DATA { (0,0): "NPP002194429582" } }
尝试的代码
use anyhow::{Ok, Result}; use hdf5::File; use ndarray::{Array, Array2}; fn main() -> Result<()> { let filename = "GMTCO_npp_d20181005_t2022358_e2024003_b35959_c20181008035331888329_cspp_dev.h5".to_string(); let file = File::open(filename)?; let dataset = file.dataset("Data_Products/VIIRS-MOD-GEO-TC/VIIRS-MOD-GEO-TC_Gran_0")?; let attribute = dataset.attr("N_Granule_ID")?; // Don't know what to use here... let v: Array2<String> = attribute.read_2d::<String>()?; Ok(()) }
遇到的问题
代码执行到读取属性内容时出错,根据属性元数据的DATASPACE SIMPLE { ( 1, 1 ) / ( 1, 1 ) },该属性是包含单个元素的2D数组,但不确定应该使用哪种读取方法和Rust数据类型。另外,hdf5-rust包仅提供了复合属性的读取示例,不清楚如何读取f32、i32、String这类非复合类型的属性。
解决方案
读取字符串属性
对于HDF5中的固定长度ASCII字符串属性,hdf5-rust提供了FixedAscii类型来匹配,再转换为Rust原生String即可。针对1x1的2D属性,代码如下:
use anyhow::{Ok, Result}; use hdf5::types::FixedAscii; use hdf5::File; use ndarray::Array2; fn main() -> Result<()> { let filename = "GMTCO_npp_d20181005_t2022358_e2024003_b35959_c20181008035331888329_cspp_dev.h5".to_string(); let file = File::open(filename)?; let dataset = file.dataset("Data_Products/VIIRS-MOD-GEO-TC/VIIRS-MOD-GEO-TC_Gran_0")?; let attribute = dataset.attr("N_Granule_ID")?; // 读取为1x1的FixedAscii数组,长度匹配属性的STRSIZE=16 let str_array: Array2<FixedAscii<16>> = attribute.read_2d()?; // 去掉末尾空终止符并转换为String let granule_id: String = str_array[[0, 0]].trim_end_nul().to_string(); println!("Granule ID: {}", granule_id); // 输出: NPP002194429582 Ok(()) }
FixedAscii<N>对应HDF5中的固定长度ASCII字符串,N必须和属性元数据里的STRSIZE一致(这里是16)。trim_end_nul()用于移除字符串末尾的空终止符,适配属性的STRPAD H5T_STR_NULLTERM设置。
读取数值类型属性(f32/i32)
对于f32、i32这类数值类型的属性,直接使用对应Rust类型读取即可,无需额外转换:
读取2D i32属性示例
// 假设属性是2D的i32类型 let int_array: Array2<i32> = attribute.read_2d()?; let target_value = int_array[[0, 0]];
读取标量f32属性示例
如果属性是标量(DATASPACE为标量),使用read_scalar():
let float_value: f32 = attribute.read_scalar()?;
读取1D f32数组属性示例
// 读取为Vec<f32> let float_vec: Vec<f32> = attribute.read_1d()?; // 或读取为ndarray的Array1 let float_array: ndarray::Array1<f32> = attribute.read_1d()?;
内容的提问来源于stack exchange,提问作者geoff.cureton
相关产品推荐
相关产品推荐

