C / C ++ HDF5 Reading a string attribute

A colleague of mine used labview to write an ASCII string as an attribute in an HDF5 file. I can see that the attribute exists and is being read, but I cannot print it.

Attribute as shown in HDF Viewer:

Date = 2015 \ 07 \ 09

So "Date" is his name.

I am trying to read an attribute using this code

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

      

Why is this happening? How can I get this string like const char*

or std::string

?

I also tried using type atype = H5Tcopy (H5T_C_S1);

and that didn't work either ...

EDIT: Here I provide a complete, standalone program as requested:

#include <string>
#include <iostream>
#include <fstream>
#include <hdf5/serial/hdf5.h>
#include <hdf5/serial/hdf5_hl.h>

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;
}

      

The printed output of this program:

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 <RETURN> to close this window...

      

Thank.

+2


source to share


2 answers


It turned out H5Aread

to be called with a reference to a char pointer ... so a pointer pointer:

H5Aread(dateAttribHandler,atype,&date);

      

Note that this does not require memory allocation. The library will reserve memory and then you can free it with H5free_memory(date)

.



This works great.

EDIT:

I only found out that this is the case when the string to be read is of variable length. If the string is of a fixed length, it is necessary to manually reserve memory with the size length+1

and even manually set the last char to null (to get a null-terminated string. There is a function in the hdf5 library that checks the String is fixed in length.

+3


source


I found that if you don't assign a date and pass the & date to H5Aread then it works. (I am using C ++ and python APIs, so I don't know C api very well.) In particular, change:

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

std::cout << H5Aread(dateAttribHandler, atype, &date) << std::endl;

      

And you should see 2015/07/09.



You might want to use the C ++ API. Using the C ++ API, your example would look like this:

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;
}

      

+1


source







All Articles