给定一个字符串向量,将它们写入HDF5数据集的最佳方法是什么?现在我正在做如下的事情:
const unsigned int MaxStrLength = 512;
struct TempContainer {
char string[MaxStrLength];
};
void writeVector (hid_t group, std::vector<std::string> const & v)
{
//
// Firstly copy the contents of the vector into a temporary container
std::vector<TempContainer> tc;
for (std::vector<std::string>::const_iterator i = v.begin ()
, end = v.end ()
; i != end
; ++i)
{
TempContainer t;
strncpy (t.string, i->c_str (), MaxStrLength);
tc.push_back (t);
}
//
// Write the temporary container to a dataset
hsize_t dims[] = { tc.size () } ;
hid_t dataspace = H5Screate_simple(sizeof(dims)/sizeof(*dims)
, dims
, NULL);
hid_t strtype = H5Tcopy (H5T_C_S1);
H5Tset_size (strtype, MaxStrLength);
hid_t datatype = H5Tcreate (H5T_COMPOUND, sizeof (TempConainer));
H5Tinsert (datatype
, "string"
, HOFFSET(TempContainer, string)
, strtype);
hid_t dataset = H5Dcreate1 (group
, "files"
, datatype
, dataspace
, H5P_DEFAULT);
H5Dwrite (dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, &tc[0] );
H5Dclose (dataset);
H5Sclose (dataspace);
H5Tclose (strtype);
H5Tclose (datatype);
}
最后,我真的很想改变上面的内容,以便:
1.它使用可变长度字符串
1.我不需要一个临时容器
我对如何存储数据没有限制,例如,如果有更好的方法,它不必是 COMPOUND 数据类型。
**编辑:**只是为了缩小问题,我对C++端的数据比较熟悉,我需要大部分帮助的是HDF5端。
谢谢你的帮助。
9条答案
按热度按时间vnjpjtjt1#
[Many感谢dirkgently帮助回答这个问题。
要在HDF 5中写入可变长度字符串,请使用以下命令:
编写容器的一种解决方案是单独编写每个元素。这可以通过hyperslabs来实现。
例如:
//...
//我的朋友
mlnl4t2r2#
下面是一些使用HDF5 c++ API编写可变长度字符串向量的工作代码。
我在其他帖子中引用了一些建议:
1.使用H5T_C_S1和H5T_VARIABLE
1.使用
string::c_str()
获取指向字符串的指针1.将指针放入
char*
的vector
中,并传递给HDF5 API创建昂贵的字符串副本是不必要的(例如
strdup()
)。c_str()
返回一个指向基础字符串的null终止数据的指针。这正是该功能的目的。当然,带有嵌入空值的字符串将不能与此...std::vector
保证具有连续的底层存储,因此使用vector
和vector::data()
与使用原始数组相同,但当然比笨重的老式c方式更整洁和安全。but5z9lq3#
如果你正在寻找更干净的代码:我建议你创建一个仿函数,它将接受一个字符串并将其保存到HDF 5容器(以所需的模式)。理查德,我用错了算法,请重新检查!
这有助于开始吗?
ulmd4ohb4#
我也遇到过类似的问题,但需要注意的是,我希望将字符串的向量存储为一个 * 属性 *。属性的棘手之处在于,我们不能使用像hyperlabs这样的花哨的数据空间特性(至少在C++ API中是这样)。
但无论哪种情况,将字符串向量输入到数据集中的单个条目中可能都很有用(例如,如果您总是希望一起读取它们)。在这种情况下,所有的魔力都来自 type,而不是数据空间本身。
基本上有四个步骤:
1.创建一个指向字符串的
vector<const char*>
。1.创建一个
hvl_t
结构,指向该向量并包含其长度。1.创建数据类型。这是一个
H5::VarLenType
包裹一个(可变长度)H5::StrType
。1.将
hvl_t
类型写入数据集。这个方法真正好的部分是,你把整个条目填充到HDF5认为是标量值的地方。这意味着使其成为属性(而不是数据集)是微不足道的。
无论您选择此解决方案还是在其自己的数据集条目中包含每个字符串的解决方案,可能也是所需性能的问题:如果你正在寻找对特定字符串的随机访问,最好将这些字符串写在数据集中,这样它们就可以被索引。如果你总是要把它们一起读出来,这个解决方案也可以。
这里有一个简短的例子,使用C++ API和一个简单的标量数据集来实现这一点:
t3psigkw5#
我迟到了,但我已经修改了利奥古德斯塔特的答案的基础上的评论有关segfaults。我用的是linux,但我没有这样的问题。我写了两个函数,一个是将std::string的向量写入到打开的H5File中给定名称的数据集,另一个是将结果数据集读回std::string的向量。请注意,在类型之间可能会有不必要的复制,但可以进行更优化。下面是用于编写和阅读的工作代码:
并阅读:
p8ekf7hl6#
如你所知,hdf5文件只接受char* 格式的数据,这是一个地址。所以最自然的方法是动态创建连续的地址(空间大小是给定的),并复制向量的值到它。
完整代码如下所示,
别忘了释放指针
weylhg0b7#
你可以使用一个简单的std::vector来代替TempContainer(你也可以将它模板化以匹配T -> basic_string)。就像这样:
l2osamch8#
为了能够 * 读取 *
std::vector<std::string>
,我发布了我的解决方案,基于Leo的提示https://stackoverflow.com/a/15220532/364818。我混合了C和C++ API。请随意编辑此内容并使其更简单。
请注意,当您调用read时,HDF5 API返回
char*
指针列表。这些char*
指针必须在使用后释放,否则会出现内存泄漏。使用示例
这是密码
tgabmvqs9#
我不知道HDF5,但你可以使用
然后这样复制字符串:
这将分配一个具有确切大小的字符串,并且在插入或阅读容器时也有很大改进(在您的示例中,复制了一个数组,在本例中只有一个指针)。也可以使用std::vector: