Atributo de cadena de lectura C / C ++ HDF5

Un colega mío usó Labview para escribir una cadena ASCII como un atributo en un archivo HDF5. Puedo ver que el atributo existe y leerlo, pero no puedo imprimirlo.

El atributo es, como se muestra en HDF Viewer:

Fecha = 2015 \ 07 \ 09

Así que “Fecha” es su nombre.

Estoy tratando de leer el atributo con este código

hsize_t sz = H5Aget_storage_size(dateAttribHandler); std::cout<<sz<<std::endl; //prints 16 hid_t atype = H5Aget_type(dateAttribHandler); std::cout<<atype<<std::endl; //prints 50331867 std::cout<<H5Aread(dateAttribHandler,atype,(void*)date)<<std::endl; //prints 0 std::cout<<date<<std::endl; //prints messy characters! //even with an std::string std::string s(date); std::cout<<s<<std::endl; //also prints a mess 

¿Por qué está pasando esto? ¿Cómo puedo obtener esta cadena como const char* o std::string ?

También intenté usar el tipo atype = H5Tcopy (H5T_C_S1); , y eso tampoco funcionó …

EDITAR: Aquí proporciono un progtwig completo y autónomo como se solicitó:

 #include  #include  #include  #include  #include  std::size_t GetFileSize(const std::string &filename) { std::ifstream file(filename.c_str(), std::ios::binary | std::ios::ate); return file.tellg(); } int ReadBinFileToString(const std::string &filename, std::string &data) { std::fstream fileObject(filename.c_str(),std::ios::in | std::ios::binary); if(!fileObject.good()) { return 1; } size_t filesize = GetFileSize(filename); data.resize(filesize); fileObject.read(&data.front(),filesize); fileObject.close(); return 0; } int main(int argc, char *argv[]) { std::string filename("../Example.hdf5"); std::string fileData; std::cout<<"Success read file into memory: "<< ReadBinFileToString(filename.c_str(),fileData)<<std::endl; hid_t handle; hid_t magFieldsDSHandle; hid_t dateAttribHandler; htri_t dateAtribExists; handle = H5LTopen_file_image((void*)fileData.c_str(),fileData.size(),H5LT_FILE_IMAGE_DONT_COPY | H5LT_FILE_IMAGE_DONT_RELEASE); magFieldsDSHandle = H5Dopen(handle,"MagneticFields",H5P_DEFAULT); dateAtribExists = H5Aexists(magFieldsDSHandle,"Date"); if(dateAtribExists) { dateAttribHandler = H5Aopen(magFieldsDSHandle,"Date",H5P_DEFAULT); } std::cout<<"Reading file done."<<std::endl; std::cout<<"Open handler: "<<handle<<std::endl; std::cout<<"DS handler: "<<magFieldsDSHandle<<std::endl; std::cout<<"Attributes exists: "<<dateAtribExists<<std::endl; hsize_t sz = H5Aget_storage_size(dateAttribHandler); std::cout<<sz<<std::endl; char* date = new char[sz+1]; std::cout<<"mem bef: "<<date<<std::endl; hid_t atype = H5Aget_type(dateAttribHandler); std::cout<<atype<<std::endl; std::cout<<H5Aread(dateAttribHandler,atype,(void*)date)<<std::endl; fprintf(stderr, "Attribute string read was '%s'\n", date); date[sz] = '\0'; std::string s(date); std::cout<<"mem aft: "<<date<<std::endl; std::cout<<s<<std::endl; H5Dclose(magFieldsDSHandle); H5Fclose(handle); return 0; } 

Salida impresa de este progtwig:

 Success read file into memory: 0 Reading file done. Open handler: 16777216 DS handler: 83886080 Attributes exists: 1 16 mem bef: 50331867 0 Attribute string read was ' P7' mem aft:  P7  P7 Press  to close this window... 

Gracias.

Resultó que se debe llamar a H5Aread con una referencia del puntero char … así que el puntero de un puntero:

 H5Aread(dateAttribHandler,atype,&date); 

Tenga en cuenta que uno no tiene que reservar memoria para eso. La biblioteca reservará memoria y luego podrá liberarla con H5free_memory(date) .

Esto funcionó bien.

EDITAR:

Aprendí que este es el caso solo cuando la cadena a leer tiene una longitud variable. Si la cadena tiene una longitud fija, entonces uno tiene que reservar manualmente la memoria con una length+1 tamaño length+1 e incluso configurar manualmente el último carácter en nulo (para obtener una cadena terminada en nulo. Hay una función en la biblioteca hdf5 que verifica si una cadena es fija en longitud

Descubrí que si no asigna la fecha y pasa la & fecha a H5Aread, entonces funciona. (Utilizo las API de C ++ y python, así que no conozco muy bien la API de C). Cambie específicamente:

 char* date = 0; // std::cout<<"mem bef: "< 

Y deberías ver 2015 \ 07 \ 09 impreso.

Es posible que desee considerar el uso de la API de C ++. Usando la API de C ++, su ejemplo se convierte en:

 std::string filename("c:/temp/Example.hdf5"); H5::H5File file(filename, H5F_ACC_RDONLY); H5::DataSet ds_mag = file.openDataSet("MagneticFields"); if (ds_mag.attrExists("Date")) { H5::Attribute attr_date = ds_mag.openAttribute("Date"); H5::StrType stype = attr_date.getStrType(); std::string date_str; attr_date.read(stype, date_str); std::cout << "date_str= <" << date_str << ">" << std::endl; }