Лучший способ открыть файлы HDF5 на С++

Я пытался найти способ обойти некоторые недостатки привязок 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++?


person apdnu    schedule 12.12.2012    source источник
comment
Другая, более сложная проблема заключается в создании вложенной группы (например, /parent/group), где родительская группа не обязательно существует. В Unix/Linux эквивалентом будет... -- Вы когда-нибудь находили хороший способ сделать это?   -  person Ben Farmer    schedule 13.05.2015
comment
Если вам дано имя вложенной группы, например /parent/group/subgroup, сначала разделите его на /parent, /parent/group и /parent/group/subgroup, а затем попробуйте открыть каждую из них по порядку. Если данная группа не существует (в C++ API вы получите H5::FileIException), создайте ее. Я написал некоторые вспомогательные функции, решающие эту проблему.   -  person apdnu    schedule 13.05.2015
comment
Недавно была такая же проблема stackoverflow.com/questions /35668056/ . Нет решения. Кроме того, я только что отметил, что H5::Exception не является производным от std::exception...?   -  person eudoxos    schedule 04.05.2016


Ответы (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);
}
person beerboy    schedule 12.12.2012

Однако в привязках HDF5 C++ создание группы, родительская группа которой не существует, вызывает исключение.

Вы можете настроить список свойств создания ссылок на создавать отсутствующие промежуточные группы и избегайте этого исключения. Например:

#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;
}
person Community    schedule 15.06.2016
comment
Это еще один аргумент в пользу использования C API, даже при написании кода на C++. В объектно-ориентированном C++ API отсутствуют многие функциональные возможности, а некоторые варианты дизайна, например создание исключений вместо установки флагов, весьма раздражают. - person apdnu; 16.06.2016
comment
Я нигде не видел, чтобы это было задокументировано, иногда ТАК такое сокровище. И этот обходной путь - то, что я определенно собираюсь использовать :) - person eudoxos; 15.01.2020