【问题标题】:Better way to open HDF5 files in C++在 C++ 中打开 HDF5 文件的更好方法
【发布时间】:2012-11-30 15:22:48
【问题描述】:

我一直在尝试想出一种方法来解决 HDF5 C++ 绑定的一些缺点。目前,我的代码中充斥着类似于以下内容的 try/catch 块:

H5::Exception::dontPrint();
H5::H5File *file = NULL;
try {
    file = new H5::H5File(fname.c_str(), H5F_ACC_RDWR);
} catch(H5::FileIException &file_exists_err) {
    file = new H5::H5File(fname.c_str(), H5F_ACC_TRUNC);
}

这不是必须的——我要做的就是打开一个文件进行读/写访问,如果它不存在,就创建它。另一个更棘手的问题是创建一个嵌套组(例如“/parent/group”),其中父组不一定存在。在 Unix/Linux 中,相当于

mkdir -p parent/group

但是,在 HDF5 C++ 绑定中,创建其父组不存在的组会引发异常。

出于这些原因,我一直有动力创建一个头文件来处理其中一些常见问题。我的第一个想法是简单地创建一组函数,例如,获取文件名和访问模式并返回 H5::H5File 对象,或者获取组名并返回组对象。然而,我认为这不太理想,因为它让使用此头文件的程序员在返回的对象上调用“删除”,即使程序员从未在自己的代码中显式调用“新”。这似乎要求内存泄漏。

因此,我的第二个想法是从 H5::H5File 和 H5::H5Group 创建一组派生类,其构造函数在文件尚不存在或组的父组存在时不会引发异常尚不存在。我对派生文件类的尝试如下:

namespace H5Utils {

class H5File : public H5::H5File {
public:
    H5File(std::string fname);
    ~H5File();
};

}

H5Utils::H5File::H5File(std::string fname)
try : H5::H5File(fname.c_str(), H5F_ACC_RDWR)
{
    std::cerr << "Opened existing file." << std::endl;
} catch(H5::FileIException &file_exists_err) {
    std::cerr << "File does not exist. Creating new file." << std::endl;
    H5::H5File(fname.c_str(), H5F_ACC_TRUNC);
}

H5Utils::H5File::~H5File() { }

我遇到的问题是双重的。首先,构造函数中的try/catch块重新抛出由

创建的异常
H5::H5File(fname.c_str(), H5F_ACC_RDWR)

当文件不存在时,程序仍然终止。第二个问题是我不确定第二个构造函数,

H5::H5File(fname.c_str(), H5F_ACC_TRUNC);

是正确的(即它是否构造父类?)有没有办法让派生类在基类的构造函数中捕获异常,然后为基类调用不同的构造函数?

更一般地说,谁能想到更好/更优雅的方法来处理 HDF5 C++ 绑定的这些缺点?

【问题讨论】:

  • “另一个更棘手的问题是创建一个嵌套组(例如“/parent/group”),其中父组不一定存在。在 Unix/Linux 中,等价于... " -- 你有没有找到一个很好的方法来做到这一点?
  • 如果给你一个嵌套组名,比如“/parent/group/subgroup”,首先将它拆分为“/parent”、“/parent/group”和“/parent/组/子组”,然后尝试按顺序打开每个。如果给定的组不存在(在 C++ API 中,您将获得 H5::FileIException),请创建它。我写了some helper functions that deal with this problem
  • 最近遇到了同样的问题stackoverflow.com/questions/35668056/…。没有解决方案。最重要的是,我刚刚注意到 H5::Exception 不是从 std::exception 派生的...?

标签: c++ inheritance hdf5


【解决方案1】:

但是,在 HDF5 C++ 绑定中,创建其父组不存在的组会引发异常。

您可以将链接创建属性列表设置为create missing intermediate groups,并避免此异常。例如:

#include "hdf5.h"

int main (void){
  hid_t lcpl, file_id, group_id;
  herr_t status;
  unsigned flag=1;

  lcpl = H5Pcreate(H5P_LINK_CREATE);
  status = H5Pset_create_intermediate_group(lcpl, flag);
  file_id = H5Fcreate("nested_groups.h5",  H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
  group_id = H5Gcreate( file_id, "/foo/bar/bop", lcpl, H5P_DEFAULT, H5P_DEFAULT );

  H5Pclose(lcpl);
  H5Gclose(group_id);
  H5Fclose(file_id);

  return status;
}

【讨论】:

  • 这是使用 C API 的另一个论据,即使使用 C++ 编写也是如此。面向对象的 C++ API 中缺少很多功能,并且一些设计选择,比如抛出异常而不是设置标志,非常烦人。
  • 我在任何地方都没有看到记录,所以有时就是这样的宝藏。这个解决方法是我肯定会使用的:)
【解决方案2】:

我更喜欢您最初创建一些简单的辅助函数的想法 - 它会更简单,并且可以最大限度地减少您必须编写和记录的代码量。此外,为了确保正确的内存管理,您可以使用shared_ptr

这是一个与您的初始示例等效的简单包装函数:

// a typedef for our managed H5File pointer
typedef std::shared_ptr<H5::H5File> H5FilePtr;

// create or open a file
H5FilePtr create_or_open(const std::string& fname)
{
    H5::Exception::dontPrint();
    H5::H5File* file = 0;

    try {
        file = new H5::H5File(fname.c_str(), H5F_ACC_RDWR);
    } catch(const H5::FileIException&) {
        file = new H5::H5File(fname.c_str(), H5F_ACC_TRUNC);
    }

    return H5FilePtr(file);
}

【讨论】:

    猜你喜欢
    • 2023-04-06
    • 2016-12-23
    • 1970-01-01
    • 2011-10-19
    • 2011-12-19
    • 2015-10-10
    • 2021-07-06
    • 2013-11-29
    • 2013-08-29
    相关资源
    最近更新 更多