【问题标题】:Reading a string array HDF5 Attribute in C++在 C++ 中读取字符串数组 HDF5 属性
【发布时间】:2017-09-29 01:13:17
【问题描述】:

我有工作的 C++ 代码,它使用存储在属性中的列名写入 HDF5 数据。我可以在 Matlab 中成功读取和处理数据,但我正在尝试创建一个 C++ 阅读器。它读取数据正常,但是当我尝试读取标题时,我只得到第一列名称。
属性创建过程的 sn-p 如下所示:

    // 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++ attributes hdf5


    【解决方案1】:

    就个人而言,要创建一个属性,它是 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 程序:

    【讨论】:

    • 谢谢@pablo_worker!你的方法解决了我的问题。
    • 能否请您告诉我如何读取字符串数组数据集?由于 DataSet 不是 Attribute 的子类,我无法重用您上面的代码。我也尝试使用成员函数 DataSet.read 读取它,但它不起作用。我的代码是这样的:char *data[dim];dataset.read((void *) data, ArrayType(PredType::C_S1), 1, &amp;dim));谢谢
    猜你喜欢
    • 2015-09-29
    • 2018-05-02
    • 2012-11-28
    • 2019-01-29
    • 2014-06-11
    • 2014-05-15
    • 2017-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多