在 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 程序中看到: