使用文件映像操作从头开始创建 hdf5 文件(内存映射 hdf5 文件)

Create hdf5 file from scratch using file image operations (memory mapped hdf5 files)

问题:我想使用内存映射 HDF5 文件进行单元测试。是否可以从头开始创建它们?

状态:我已经阅读了 HDF5 文件图像操作 document,并尝试应用它。根据使用的确切参数,我得到一个无效的文件标识符 (-1),或者后续创建数据集失败。

通常我们的单元测试会编写新的测试文件,模仿用户将新创建的数据保存到磁盘上的文件中。所以还没有一个现有的文件。在阅读 hdf5 文件图像操作文档时,假设设置了初始文件图像。我没有任何 - 因为我试图通过我的测试尽可能接近实际用户场景。可以从空缓冲区创建这样的文件吗?

static const unsigned int FileSize = 1024 * 1024 * 100;
std::vector<unsigned char> buffer(FileSize, 0);     // initialize buffer with zeroes
int flags = H5LT_FILE_IMAGE_DONT_COPY | 
            H5LT_FILE_IMAGE_OPEN_RW | 
            H5LT_FILE_IMAGE_DONT_RELEASE;
m_file = H5LTopen_file_image(static_cast<void*>(buffer.data()), buffer.size(), flags);

如果想像示例中那样保留缓冲区的所有权,我没有获得有效的文件 ID。我怀疑是 HDF5 中的错误,但不幸的是留下了标志 H5LT_FILE_IMAGE_DONT_COPY | H5LT_FILE_IMAGE_DONT_RELEASE out 也没用。

显然 H5LTOpen_file_image 包装了一些也允许创建虚拟文件的调用。这都是核心文件驱动管理的。可以通过将一些参数传递给核心文件驱动程序来检索所需的结果。

auto propertyList = H5Pcreate(H5P_FILE_ACCESS);
auto h5Result = H5Pset_fapl_core(propertyList, m_buffer.GetSize(), false);
assert(h5Result >= 0 && "H5Pset_fapl_core failed");
m_file = H5Fcreate(name, flags, H5P_DEFAULT, propertyList);

调用 H5Pset_fapl_core 的最后一个参数设置 "virtual backing store" 的布尔值。如果设置为 false,则文件内容不会写入磁盘。

请注意,最后我不得不使用开头提到的文档中的所有高级技巧 post 才能真正使所有功能正常工作。该文档是一个很好的参考,但有点过时(枚举在最新版本中具有不同但相似的命名)。

基于@FreekNossin 的回答,这是一个更完整的代码,使用可用的 c++ API:

#include<H5Cpp.h>

/* create the HDF5 file image first */
H5::FileAccPropList accPList=H5::FileAccPropList::DEFAULT;
// https://confluence.hdfgroup.org/display/HDF5/H5P_SET_FAPL_CORE
herr_t h5err=H5Pset_fapl_core(accPList.getId(),/* memory increment size: 4M */1<<22,/*backing_store*/false);
if(h5err<0) throw std::runtime_error("H5P_set_fapl_core failed.");
H5::H5File h5file("whatever",H5F_ACC_TRUNC,H5::FileCreatPropList::DEFAULT,accPList);

/* add data like usual */
H5::Group grp=h5file.createGroup("somegroup");
/* ... */

/* get the image */
h5file.flush(H5F_SCOPE_LOCAL); // probably not necessary
ssize_t imgSize=H5Fget_file_image(h5file.getId(),NULL,0); // first call to determine size
std::vector<char> buf(imgSize);
H5Fget_file_image(h5file.getId(),buf.data(),imgSize); // second call to actually copy the data into our buffer

编辑: 代码中有一个陷阱:如果两个线程打开同一个 "whatever"(presudo)文件,则会抛出 H5::FileIException: unable to truncate a file which is already open。我使用的解决方法是将堆栈 (thread-local) 变量的地址放入名称中:

int _var=0;
std::string hdf5name(("whatever+std::to_string((uintptr_t)&_var)).c_str());