在 Fortran 中获取 HDF5 文件名的长度?

Posted

技术标签:

【中文标题】在 Fortran 中获取 HDF5 文件名的长度?【英文标题】:Get length of HDF5 filename in Fortran? 【发布时间】:2021-08-30 18:01:51 【问题描述】:

我正在尝试在 Fortran 中获取 HDF5 对象的文件名,为此我事先不知道文件名的长度。 HDF5 文档说这可以通过将 NULL 传递给 h5fget_name 来完成:

如果决定所需大小值的名称长度未知,则可以通过将名称设置为 NULL 来进行初步 H5Fget_name 调用。

但是,目前尚不清楚如何从 Fortran 代码中完成此操作。根据文档中的上述语言,这样的事情应该可以工作:

  function get_hdf5_filename(obj_id) result(filename)

    use hdf5
    use iso_c_binding, ONLY: c_null_ptr

    ! Arguments
    integer(HID_T), intent(in)::obj_id
        !! Handle of HDF5 object

    ! Result
    character(:), allocatable::filename

    integer(SIZE_T)::size = 0
        !! Length of filename

    integer::hdferr
        !! HDF5 error code

    call h5fget_name_f(obj_id, c_null_ptr, size, hdferr)

    allocate (character(size)::filename)

    call h5fget_name_f(obj_id, filename, size, hdferr)

  end function get_hdf5_filename

但是,gfortran 不会编译上述内容并给出类型不匹配错误:

Error: Type mismatch in argument 'buf' at (1); passed TYPE(c_ptr) to CHARACTER(1)

【问题讨论】:

注意 c_null_ptr 与 NULLified fortran 指针不同 【参考方案1】:

可以通过将文件名变量声明为指针并在初始调用 h5fget_name_f 之前将其取消来传递 null:

  function get_hdf5_filename(obj_id) result(filename)

    use hdf5
    use iso_c_binding, ONLY: c_null_ptr

    ! Arguments
    integer(HID_T), intent(in)::obj_id
        !! Handle of HDF5 object

    ! Result
    character(:), pointer::filename

    integer(SIZE_T)::size = 50
        !! Length of filename

    integer::hdferr
        !! HDF5 error code

    nullify(filename)

    call h5fget_name_f(obj_id, filename, size, hdferr)

    ! HDF5 needs one more character (probably for the null character terminating the string), so we allocate filename to length size+1
    allocate (character(size+1)::filename)

    call h5fget_name_f(obj_id, filename, size, hdferr)

    ! Remove last character from the returned string
    filename => filename(1:size)

  end function get_hdf5_filename

请注意,h5fget_name_f 在传递的字符串中需要一个额外的字符(可能用于终止空字符),因此必须为名称指针分配比 size 参数中设置的值长一个字符。可以通过使用数组切片语法将文件指针重定向到排除最后一个字符的子集来删除终止的空值(上例中的filename => filename(1:size))。

【讨论】:

Fortran 语言不允许将分离的指针作为与普通(非指针、非可选,...)伪参数关联的实际参数。鉴于此 Fortran API 在 HDF5 1.12 中实现的方式,预计可能会出现随机运行时爆炸。另外,这个 HDF5 Fortran API 的实现可以说是被破坏了。 @IanH,从您写的内容来看,在分配之前(可靠地)获取名称长度的唯一方法是直接调用 H5Fget_name 。那是对的吗?那么问题是是否有可靠的方法将整数(HID_T)从 Fortran 转换为 hid_t。 h5fget_name_c 只是使用强制转换,但我怀疑 HDF5 开发人员打算在客户端代码中完成这种事情。 我在 HDF5 github 存储库 (github.com/HDFGroup/hdf5/issues/824) 上提交了关于 h5fget_name_f 的实现与文档中描述的行为不一致的问题报告。【参考方案2】:

一种可能的解决方案是创建一个 C 函数,该函数返回给定 HDF5 对象的文件名长度:

#include "hdf5.h"
#include "H5f90i.h"

int_f get_hdf5_filename_length(hid_t_f *obj_id)
  return H5Fget_name((hid_t)*obj_id, NULL, 0);

可以通过以下方式从 Fortran 调用:

  function get_hdf5_filename(obj_id) result(filename)

    use hdf5
    use iso_c_binding, ONLY: c_null_ptr

    interface
       function get_hdf5_filename_length(obj_id) bind(c) result(length)
         use hdf5
         integer(HID_T)::obj_id
         integer(SIZE_T)::length
       end function get_hdf5_filename_length
    end interface

    ! Arguments
    integer(HID_T), intent(in)::obj_id
        !! Handle of HDF5 object

    ! Result
    character(:), pointer::filename

    integer(SIZE_T)::size = 50
        !! Length of filename

    integer::hdferr
        !! HDF5 error code

    integer::i
        !! Loop counter

    size = get_hdf5_filename_length(obj_id)

    ! filename has to be allocated to size+1 to allow for the terminating null
    ! of the filename string in C
    allocate (character(size+1)::filename)

    ! h5fget_name_f uses len_trim to determine the buffer length,
    ! which requires the buffer be filled with non-whitespace characters
    ! in order to work correctly
    do i = 1, size + 1
      filename(i:i) = 'a'
    end do

    ! Get the filename
    call h5fget_name_f(obj_id, filename, size, hdferr)

    ! Remove the null character from the end of the string
    filename => filename(1:size)

  end function get_hdf5_filename

请注意,仅将字符串缓冲区分配到正确的大小是不够的;它还需要在传递给h5fget_name_f 之前填充非空白字符,因为h5fget_name_f 在传递的缓冲区上调用len_trim 并使用结果来确定允许的最大文件名长度。

【讨论】:

我提交了一份关于 HDF5 github 存储库 (github.com/HDFGroup/hdf5/issues/825) 的问题报告,要求在传递给 h5fget_name_f 之前填充字符串缓冲区(未记录)。

以上是关于在 Fortran 中获取 HDF5 文件名的长度?的主要内容,如果未能解决你的问题,请参考以下文章

HDF5 用于使用 fortran 编写的数据文件

在 fortran 中将写入附加到 hdf5 文件

从 Fortran 中的 HDF 文件中读取长度未知的数组

在 FORTRAN / MPI / HDF5 ( 1.10.1 ) 中使用 h5fopen_f 打开文件时出错

在 Fortran 中读取 HDF5 数据集的子集时出现问题

致命错误:在 (1) 处打开的文件“hdf5.mod”不是 GNU Fortran 模块文件