使用文件映射操作(内存映射的hdf5文件),从头创建hdf5文件

3

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

状态:我已经阅读了HDF5文件映像操作 文档,并尝试应用它。根据使用的确切参数,我会得到一个无效的文件标识符(-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也没有起作用。
2个回答

3

显然,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 函数的最后一个参数设置“虚拟后备存储”的布尔值。如果设置为 false,则文件内容不会写入磁盘。
请注意,最终我不得不使用开帖引用的文档中提到的所有高级技巧来确保所有功能正常工作。该文档是很好的参考资料,但有点过时(枚举在最新版本中具有不同但类似的命名)。

3
在 @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"(伪)文件,会抛出H5::FileIException:无法截断已经打开的文件。我使用的解决方法是每次生成唯一的名称,就像这样:

static std::atomic<int> _var=0;
std::string hdf5name(("whatever+std::to_string(_var++)).c_str());

我想知道,是否有更可靠的方法来获取线程安全的唯一文件名? - floatdrop
你的意思是什么?就我所看到的,这个完全可靠;只是不够优雅。 - eudoxos
无法保证&_var不会在长期使用中(比如几天)返回相同的地址,而hdf文件仍在使用。 - floatdrop
True。例如,static int a=0;再使用 a++ 来构造伪文件名将是唯一的(除非您溢出 int)。 - eudoxos
是的,但这会导致数据竞争,所以在修改之前一定要使用互斥锁锁定 a - floatdrop
1
是的。然后是 static std::atomic<int> a=0;a++ - eudoxos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接