Creating and updating string attribute - only first character stored?

I tried creating and updating a string attribute but h5dump prints only the first character, is it a dataspace definition problem ?

			std::string filepath;
			hid_t acpl = H5Pcreate(H5P_ATTRIBUTE_CREATE);
			assert(acpl != H5I_INVALID_HID);

			// use UTF-8 encoding for the attribute name
			herr_t status = H5Pset_char_encoding(acpl, H5T_CSET_UTF8);
			assert(status >= 0);

			// create a scalar (singleton) attribute
			hid_t fspace = H5Screate(H5S_SCALAR);
			assert(fspace != H5I_INVALID_HID);

			hid_t attr = H5Acreate2(file, "filepath", H5T_C_S1, fspace, acpl,
			H5P_DEFAULT);
			assert(attr != H5I_INVALID_HID);

			// update the attribute value
			char testbuff[] = "Hello world";
			status = H5Awrite(attr, H5T_C_S1, testbuff);
			assert(status >= 0);

h5dump first couple of lines

HDF5 "squab.h5" {
GROUP "/" {
   ATTRIBUTE "filepath" {
      DATATYPE  H5T_STRING {
         STRSIZE 1;
         STRPAD H5T_STR_NULLTERM;
         CSET H5T_CSET_ASCII;
         CTYPE H5T_C_S1;
      }
      DATASPACE  SCALAR
      DATA {
      (0): "H"
      }
   }
   GROUP "PolyMesh" {

Hi @yue.nicholas,

I believe variable testbuff needs to be a pointer of a pointer for its content to be written properly into the attribute. In addition, you should set the size type as variable - something similar to H5Tset_size(type, H5T_VARIABLE);.

Alternatively, you may want to give HDFql a try as it alleviates the user from HDF5 low-level details. To write a string into an attribute using HDFql in C++ could be done as follows:

// create an HDF5 file named 'squab.h5' and use (i.e. open) it
HDFql::execute("CREATE AND USE FILE squab.h5");

// create an attribute named 'filepath' and write string 'Hello world' into it
HDFql::execute("CREATE ATTRIBUTE filepath AS UTF8 VARCHAR VALUES(\"Hello world\")");

Hope it helps!

2 Likes

@contact Thanks for the tip.

I have rework the code, the following works for me

			std::string filepath;
			hid_t acpl = H5Pcreate(H5P_ATTRIBUTE_CREATE);
			assert(acpl != H5I_INVALID_HID);

			// use UTF-8 encoding for the attribute name
			herr_t status = H5Pset_char_encoding(acpl, H5T_CSET_UTF8);
			assert(status >= 0);

			const char* testbuff[1] = {"Hello world"};

			// create a scalar (singleton) attribute
			hid_t fspace = H5Screate(H5S_SCALAR);
			assert(fspace != H5I_INVALID_HID);

			// create a variable length string type
		    hid_t attr_type = H5Tcopy(H5T_C_S1);
			status = H5Tset_size(attr_type, H5T_VARIABLE);
			assert(status >= 0);

			hid_t attr = H5Acreate2(file, "filepath", attr_type, fspace, acpl,H5P_DEFAULT);
			assert(attr != H5I_INVALID_HID);

			// update the attribute value
			status = H5Awrite(attr, attr_type, &testbuff);
			assert(status >= 0);
			H5Sclose(fspace);
			H5Aclose(attr);
1 Like

Glad you’ve figured it out, @yue.nicholas. For completeness:

H5T_C_S1 is shorthand for

DATATYPE  H5T_STRING {
         STRSIZE 1;
         STRPAD H5T_STR_NULLTERM;
         CSET H5T_CSET_ASCII;
         CTYPE H5T_C_S1;
      }

If you prefer a fixed-(byte-)length string, you could also use

status = H5Tset_size(attr_type, 11);

This should yield

DATATYPE  H5T_STRING {
         STRSIZE 11;
         STRPAD H5T_STR_NULLTERM;
         CSET H5T_CSET_ASCII;
         CTYPE H5T_C_S1;
      }
DATASPACE  SCALAR
      DATA {
      (0): "Hello World"
      }

G.

2 Likes