C / C ++ HDF5 Чтение строкового атрибута

Мой коллега использовал labview для записи строки ASCII в качестве атрибута в файле HDF5. Я вижу, что атрибут существует, и читаю его, но не могу его распечатать.

Атрибут, как показано в HDF Viewer:

Дата = 2015 \ 07 \ 09

Так что «Дата» — это его имя.

Я пытаюсь прочитать атрибут с этим кодом

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

Почему это происходит? Как я могу получить эту строку как const char* или же std::string?

Я пытался также использовать тип atype = H5Tcopy (H5T_C_S1);и это тоже не сработало …

РЕДАКТИРОВАТЬ:
Здесь я предоставляю полную, автономную программу, как было запрошено:

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

Печатная продукция этой программы:

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...

Благодарю.

2

Решение

Оказалось, что H5Aread должен вызываться со ссылкой на указатель на символ … так указатель на указатель:

H5Aread(dateAttribHandler,atype,&date);

Имейте в виду, что для этого не нужно резервировать память. Библиотека зарезервирует память, а затем вы можете освободить ее с помощью H5free_memory(date),

Это работало нормально.

РЕДАКТИРОВАТЬ:

Я узнал, что это имеет место только тогда, когда строка для чтения имеет переменную длину. Если строка имеет фиксированную длину, нужно вручную зарезервировать память с размером length+1 и даже вручную установите последний символ в null (чтобы получить строку с нулевым символом в конце. В библиотеке hdf5 есть функция, которая проверяет, является ли строка фиксированной длины.

3

Другие решения

Я обнаружил, что если вы не выделите дату и передадите &дата в H5Aread, значит работает. (Я использую API C ++ и Python, поэтому я не очень хорошо знаю API C.)

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

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

И вы должны увидеть 2015 \ 07 \ 09 напечатанным.

Вы можете рассмотреть возможность использования API C ++. Используя C ++ API, ваш пример становится:

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

По вопросам рекламы [email protected]