TDirectory as TFile key

I would like to loop on the data objects of a TFile, and handle histograms and subdirectories differently:

This example - which I tested with a file with many direstories in it - supposed to read in a file and print out the content type. However, it fails to do so and prints 0-s for the directory entries.

for(auto&& key: *(file -> GetListOfKeys()))
{
	bool is_directory = dynamic_cast<TDirectory*>(key) ? true : false;
	bool is_histogram = dynamic_cast<TH1*>       (key) ? true : false;
	std::cout << key -> GetName() << " -> is directory? " << is_directory << "; is histogram? " << is_histogram << '\n';
}

What is the proper way to do this?

Hi,

I think you got it right. You can speed up the dynamic_cast, but here we are talking about 2nd order refinements, especially at this level, exploiting ROOT reflection (key->GetClassName() - see for example Finding all objects in a root file, regardless of directries)

Cheers,
D

But it does not work, is_directory is 0 even for directories. Also, I get this error for the GetKeyName() approach: 'class TObject' has no member named 'GetClassName'

To get the object corresponding to an object of class TKey, you need to read this object from file first. Something like this should work:

bool is_directory = dynamic_cast<TDirectory*>(key->ReadObj()) ? true : false;

I am not sure how ROOT handles the memory in this case, i.e., if each call to ReadObj returns a new object, or whether the old one is recycled. In any case, as you first have to get the complete object from file, and not just some metadata, this approach will perform worse than what Danilo proposed.

I get the same error here, since key is already of class TObject (but its class inside root is a TKey):

error: ‘class TObject’ has no member named ‘ReadObj’

Just cast the TObject to an TKey in this case:

for(auto&& element: *(file->GetListOfKeys()))
{
	TKey* key = dynamic_cast<TKey*>(element);
	bool is_directory = dynamic_cast<TDirectory*>(key->ReadObj()) ? true : false;
}

error: cannot dynamic_cast ‘element’ (of type ‘class TObject*’) to type ‘class TKey*’ (target is not pointer or reference to complete type)

You need to add

#include "TKey.h"

With 6.12/04
You can replace:

with

for(auto key : TRangeDynCast<TKey>( cl->GetListOfKeys() )) {
   if (!key) continue;
   ...

With any version of ROOT, for the selection, you can use

      TObject *obj = key->ReadObj();
      TDirectory *dir = dynamic_cast<TDirectory*>( obj );
      if (dir) {
           ....
           continue;
      }
      TH1 *hist = dynamic_cast<THist*>( obj );
      if (hist) {
         ...
         continue;
     }

You can even skip the reading of the object by using TKey::GetClassName

TClass *cl = TClass::GetClass( key->GetClassName() );
if (cl->InheritsFrom(TDirectory::Class())) {
     ...
} else if (cl-InheritsFrom(TH1::Class())) {
    ...
}

Cheers,
Philippe.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.