2012-12-12 22 views
8

我一直在想辦法解決HDF5 C++綁定的一些缺點。目前,我的代碼充斥着類似於以下try/catch塊:在C++中打開HDF5文件的更好方法

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對象,或者獲取組名並返回組對象。然而,我認爲這並不理想,因爲它使得使用這個頭文件的程序員在返回的對象上調用「delete」,即使程序員從未在他們自己的代碼中明確地調用「new」。這似乎是要求內存泄漏。

因此,我的第二個想法是從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++綁定的這些缺點嗎?

+0

「另一個棘手的問題是創建一個嵌套組(例如」/ parent/group「),其中父組不一定存在。 「 - 你有沒有找到一個很好的方法來做到這一點? –

+2

如果給定一個嵌套組名稱,比如「/ parent/group/subgroup」,首先將它分成「/ parent」,「/ parent/group」和「/ parent/group/subgroup」,然後嘗試按順序打開每一個。如果給定的組不存在(在C++ API中,您將得到一個'H5 :: FileIException'),創建它。我寫了一些[處理這個問題的幫助函數](https://github.com/gregreen/h5utils/blob/master/src/h5utils.cpp#L92)。 – Thucydides411

+0

最近有同樣的問題http://stackoverflow.com/questions/35668056/test-group-existence-in-hdf5-c。沒有解決方案。最重要的是,我剛纔注意到H5 :: Exception不是從std :: exception ...派生的? – eudoxos

回答

8

我更喜歡創建一些簡單的輔助函數的初始想法 - 它會更簡單,並最小化您必須編寫和記錄的代碼量。此外,爲確保正確的內存管理,您可以使用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); 
} 
3

然而,在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; 
} 
+0

這是使用C API的另一個參數,即使在使用C++編寫時也是如此。在面向對象的C++ API中缺少很多功能,並且一些設計選擇(比如拋出異常而不是設置標誌)非常煩人。 – Thucydides411