在 C++ 中读取字符串数组 HDF5 属性
Reading a string array HDF5 Attribute in C++
我有可用的 C++ 代码,它使用存储在属性中的列名写入 HDF5 数据。我可以在 Matlab 中成功读取和处理数据,但我正在尝试创建 C++ reader。它读取数据正常,但是当我尝试读取 header 时,我只得到第一列名称。
属性创建过程的片段如下所示:
// Snip of working code during the creation/recording of a DataSet named mpcDset:
std::vector<std::string> lcFieldnames;
lcFieldnames.clear();
lcFieldnames.push_back("Field1");
lcFieldnames.push_back("Field2");
lcFieldnames.push_back("Field3");
uint lnMaxStringLen = 10;
uint lnNumFields = lcFieldnames.size();
char* lpnBuffer = new char[lnNumFields*lnMaxStringLen];
memset((void*)lpnBuffer,0,lnNumFields*lnMaxStringLen);
int lnCount = 0;
for (auto& lnIndex : lcFieldnames)
{
lnIndex.copy(lpnBuffer + (lnCount *
lnMaxStringLen), lnMaxStringLen -1);
lnCount++;
}
hsize_t lpnHwriteDims[] = { lnNumFields, lnMaxStringLen };
H5::DataSpace lcAdspace(2, lpnHwriteDims, NULL);
H5::Attribute lcAttr = mpcDset->createAttribute(
std::string("header"),
H5::PredType::NATIVE_CHAR, lcAdspace);
lcAdspace.close();
lcAttr.write(H5::PredType::NATIVE_CHAR, lpnBuffer);
lcAttr.close();
delete [] lpnBuffer;
有问题的代码如下所示:
// In another program, given an opened DataSet named mpcDset:
H5::Attribute lcAttr = mpcDset.openAttribute("header");
H5::DataType lcType = lcAttr.getDataType();
hsize_t lnSize = lcAttr.getStorageSize();
char* lpnBuffer = new char[lnSize];
lcAttr.read(lcType, lpnBuffer);
for (uint i=0;i<lnSize; i++)
{
std::cout<<lpnBuffer[i];
}
std::cout<<std::endl;
delete [] lpnBuffer;
lcAttr.close();
lnSize 对于所有三个字段都足够大(通过检查),但只输出 "Field1"。关于我做错了什么有什么建议吗?
就我个人而言,要在 C++ 中创建一个字符串列表属性,我会执行以下操作(类似的操作):
这段代码会写入一个属性,它是 3 个字符串,然后它会读取每个字符串。
#include "H5Cpp.h"
#ifndef H5_NO_NAMESPACE
using namespace H5;
#endif
#include <iostream>
#include <string>
#include <vector>
using std::string;
using std::vector;
using std::cout;
using std::endl;
int main(int argc, char *argv[])
{
//WRITE ATTRIBUTE
{
try
{
//Example:
//Suppose that in the HDF5 file: 'myH5file_forExample.h5' there is a dataset named 'channel001'
//In that dataset we will create an attribute named 'Column_Names_Attribute'
//That attribute is a list of strings, each string is of variable length.
//The data of the attribute.
vector<string> att_vector;
att_vector.push_back("ColName1");
att_vector.push_back("ColName2 more characters");
att_vector.push_back("ColName3");
//HDF5 FILE
H5::H5File m_h5File;
m_h5File = H5File("myH5file_forExample.h5", H5F_ACC_RDWR); //Open file for read and write
DataSet theDataSet = m_h5File.openDataSet("/channel001"); //Open dataset
H5Object * myObject = &theDataSet;
//DATASPACE
StrType str_type(PredType::C_S1, H5T_VARIABLE);
const int RANK = 1;
hsize_t dims[RANK];
dims[0] = att_vector.size(); //The attribute will have 3 strings
DataSpace att_datspc(RANK, dims);
//ATTRIBUTE
Attribute att(myObject->createAttribute("Column_Names_Attribute" , str_type, att_datspc));
//Convert the vector into a C string array.
//Because the input function ::write requires that.
vector<const char *> cStrArray;
for(int index = 0; index < att_vector.size(); ++index)
{
cStrArray.push_back(att_vector[index].c_str());
}
//WRITE DATA
//att_vector must not change during this operation
att.write(str_type, (void*)&cStrArray[0]);
}
catch(H5::Exception &e)
{
std::cout << "Error in the H5 file: " << e.getDetailMsg() << endl;
}
}
//READ ATTRIBUTE
{
try
{
//HDF5 FILE
H5::H5File m_h5File;
m_h5File = H5File("myH5file_forExample.h5", H5F_ACC_RDONLY); //Open file for read
DataSet theDataSet = m_h5File.openDataSet("/channel001"); //Open dataset
H5Object * myObject = &theDataSet;
//ATTRIBUTE
Attribute att(myObject->openAttribute("Column_Names_Attribute"));
// READ ATTRIBUTE
// Read Attribute DataType
DataType attDataType = att.getDataType();
// Read the Attribute DataSpace
DataSpace attDataSpace = att.getSpace();
// Read size of DataSpace
// Dimensions of the array. Since we are working with 1-D, this is just one number.
hsize_t dim = 0;
attDataSpace.getSimpleExtentDims(&dim); //The number of strings.
// Read the Attribute Data. Depends on the kind of data
switch(attDataType.getClass())
{
case H5T_STRING:
{
char **rdata = new char*[dim];
try
{
StrType str_type(PredType::C_S1, H5T_VARIABLE);
att.read(str_type,(void*)rdata);
for(int iStr=0; iStr<dim; ++iStr)
{
cout << rdata[iStr] << endl;
delete[] rdata[iStr];
}
delete[] rdata;
break;
}
catch(...)
{
for(int iStr=0; iStr<dim; ++iStr)
{
delete[] rdata[iStr];
}
delete[] rdata;
throw std::runtime_error("Error while reading attribute.");
}
throw std::runtime_error("Not valid rank.");
break;
}
case H5T_INTEGER:
{
break;
}
case H5T_FLOAT:
{
break;
}
default:
{
throw std::runtime_error("Not a valid datatype class.");
}
}
}
catch(H5::Exception &e)
{
std::cout << "Error in the H5 file: " << e.getDetailMsg() << endl;
}
catch(std::runtime_error &e)
{
std::cout << "Error in the execution: " << e.what() << endl;
}
}
return 0;
}
写入操作的结果,在 HDFview 程序中看到:
我有可用的 C++ 代码,它使用存储在属性中的列名写入 HDF5 数据。我可以在 Matlab 中成功读取和处理数据,但我正在尝试创建 C++ reader。它读取数据正常,但是当我尝试读取 header 时,我只得到第一列名称。
属性创建过程的片段如下所示:
// Snip of working code during the creation/recording of a DataSet named mpcDset:
std::vector<std::string> lcFieldnames;
lcFieldnames.clear();
lcFieldnames.push_back("Field1");
lcFieldnames.push_back("Field2");
lcFieldnames.push_back("Field3");
uint lnMaxStringLen = 10;
uint lnNumFields = lcFieldnames.size();
char* lpnBuffer = new char[lnNumFields*lnMaxStringLen];
memset((void*)lpnBuffer,0,lnNumFields*lnMaxStringLen);
int lnCount = 0;
for (auto& lnIndex : lcFieldnames)
{
lnIndex.copy(lpnBuffer + (lnCount *
lnMaxStringLen), lnMaxStringLen -1);
lnCount++;
}
hsize_t lpnHwriteDims[] = { lnNumFields, lnMaxStringLen };
H5::DataSpace lcAdspace(2, lpnHwriteDims, NULL);
H5::Attribute lcAttr = mpcDset->createAttribute(
std::string("header"),
H5::PredType::NATIVE_CHAR, lcAdspace);
lcAdspace.close();
lcAttr.write(H5::PredType::NATIVE_CHAR, lpnBuffer);
lcAttr.close();
delete [] lpnBuffer;
有问题的代码如下所示:
// In another program, given an opened DataSet named mpcDset:
H5::Attribute lcAttr = mpcDset.openAttribute("header");
H5::DataType lcType = lcAttr.getDataType();
hsize_t lnSize = lcAttr.getStorageSize();
char* lpnBuffer = new char[lnSize];
lcAttr.read(lcType, lpnBuffer);
for (uint i=0;i<lnSize; i++)
{
std::cout<<lpnBuffer[i];
}
std::cout<<std::endl;
delete [] lpnBuffer;
lcAttr.close();
lnSize 对于所有三个字段都足够大(通过检查),但只输出 "Field1"。关于我做错了什么有什么建议吗?
就我个人而言,要在 C++ 中创建一个字符串列表属性,我会执行以下操作(类似的操作): 这段代码会写入一个属性,它是 3 个字符串,然后它会读取每个字符串。
#include "H5Cpp.h"
#ifndef H5_NO_NAMESPACE
using namespace H5;
#endif
#include <iostream>
#include <string>
#include <vector>
using std::string;
using std::vector;
using std::cout;
using std::endl;
int main(int argc, char *argv[])
{
//WRITE ATTRIBUTE
{
try
{
//Example:
//Suppose that in the HDF5 file: 'myH5file_forExample.h5' there is a dataset named 'channel001'
//In that dataset we will create an attribute named 'Column_Names_Attribute'
//That attribute is a list of strings, each string is of variable length.
//The data of the attribute.
vector<string> att_vector;
att_vector.push_back("ColName1");
att_vector.push_back("ColName2 more characters");
att_vector.push_back("ColName3");
//HDF5 FILE
H5::H5File m_h5File;
m_h5File = H5File("myH5file_forExample.h5", H5F_ACC_RDWR); //Open file for read and write
DataSet theDataSet = m_h5File.openDataSet("/channel001"); //Open dataset
H5Object * myObject = &theDataSet;
//DATASPACE
StrType str_type(PredType::C_S1, H5T_VARIABLE);
const int RANK = 1;
hsize_t dims[RANK];
dims[0] = att_vector.size(); //The attribute will have 3 strings
DataSpace att_datspc(RANK, dims);
//ATTRIBUTE
Attribute att(myObject->createAttribute("Column_Names_Attribute" , str_type, att_datspc));
//Convert the vector into a C string array.
//Because the input function ::write requires that.
vector<const char *> cStrArray;
for(int index = 0; index < att_vector.size(); ++index)
{
cStrArray.push_back(att_vector[index].c_str());
}
//WRITE DATA
//att_vector must not change during this operation
att.write(str_type, (void*)&cStrArray[0]);
}
catch(H5::Exception &e)
{
std::cout << "Error in the H5 file: " << e.getDetailMsg() << endl;
}
}
//READ ATTRIBUTE
{
try
{
//HDF5 FILE
H5::H5File m_h5File;
m_h5File = H5File("myH5file_forExample.h5", H5F_ACC_RDONLY); //Open file for read
DataSet theDataSet = m_h5File.openDataSet("/channel001"); //Open dataset
H5Object * myObject = &theDataSet;
//ATTRIBUTE
Attribute att(myObject->openAttribute("Column_Names_Attribute"));
// READ ATTRIBUTE
// Read Attribute DataType
DataType attDataType = att.getDataType();
// Read the Attribute DataSpace
DataSpace attDataSpace = att.getSpace();
// Read size of DataSpace
// Dimensions of the array. Since we are working with 1-D, this is just one number.
hsize_t dim = 0;
attDataSpace.getSimpleExtentDims(&dim); //The number of strings.
// Read the Attribute Data. Depends on the kind of data
switch(attDataType.getClass())
{
case H5T_STRING:
{
char **rdata = new char*[dim];
try
{
StrType str_type(PredType::C_S1, H5T_VARIABLE);
att.read(str_type,(void*)rdata);
for(int iStr=0; iStr<dim; ++iStr)
{
cout << rdata[iStr] << endl;
delete[] rdata[iStr];
}
delete[] rdata;
break;
}
catch(...)
{
for(int iStr=0; iStr<dim; ++iStr)
{
delete[] rdata[iStr];
}
delete[] rdata;
throw std::runtime_error("Error while reading attribute.");
}
throw std::runtime_error("Not valid rank.");
break;
}
case H5T_INTEGER:
{
break;
}
case H5T_FLOAT:
{
break;
}
default:
{
throw std::runtime_error("Not a valid datatype class.");
}
}
}
catch(H5::Exception &e)
{
std::cout << "Error in the H5 file: " << e.getDetailMsg() << endl;
}
catch(std::runtime_error &e)
{
std::cout << "Error in the execution: " << e.what() << endl;
}
}
return 0;
}
写入操作的结果,在 HDFview 程序中看到: