Re: moving a TDirectory from one TFile to another

stefan kluth (skluth@mh1.lbl.gov)
Fri, 4 Dec 1998 11:51:33 -0800 (PST)


On Fri, 4 Dec 1998, Rene Brun wrote:
> Your code below will work only for simple cases. It also implies
> that your objects must be in memory first.
> The development of a true Cp and Mv functions is more work.
> Copying/Moving should not require the import in memory with object
> expansion. A simple transfert of the stream of bytes is required.
> The difficulty is to support trees in this mode.

Hello,

I have a revised version of my code on roottalk which will correctly
handle TH1 derivatives and TDirectories in memory. Of course you are right
that requirering things to be in memory is a limitation. For general
interest, here is the code.

...

bool RooTupleManager::setFileName( const char* file ) {

// Make sure we are at the top of the current file, then save:
checkFile();
rtfilep->cd();
write();

// Create the new file and transfer all objects from existing to new
// file. Function movedir will call itself recursively for directories.
TFile* filep= new TFile( file, "RECREATE",
"Created for you again by RooTupleManager" );
movedir( rtfilep, filep );

// Now we can safely get rid of the old file:
delete rtfilep;
rtfilep= filep;

// The End:
return true;

}

// Recursively move contents of olddir to newdir:
void RooTupleManager::movedir( TDirectory* olddir, TDirectory* newdir ) {

TList* list1= olddir->GetList();
TIter iter( list1 );
TObject* obj= 0;
while( obj= iter.Next() ) {
if( obj->InheritsFrom( "TH1" ) ) {
// TH1::SetDirectory does all the work for us:
((TH1*)obj)->SetDirectory( newdir );
}
else if( strcmp( obj->ClassName(), "TDirectory" ) == 0 ) {
// Have to do it by hand recursively for TDirectory:
list1->Remove( obj );
TDirectory* dir= newdir->mkdir( obj->GetName() );
movedir( (TDirectory*)obj, dir );
}
}
return;

}

...

I have to create new TDirectories when I move their contents, because they
know about their file and this can't be changed.

It would perhaps be better, if TDirectory would not hold a pointer to the
file, but would rather ask its "mother" for the file pointer. You could
have (public) member functions

TFile* TDirectory::GetFile() { return fmother->GetFile(); }

and

TFile* Tfile::GetFile() { return this; }

So, when you need to the know the file a TDirectory is attached to the
call will cascade up the directory tree until you hit the current TFile.
If you move a TDirectory to another directory tree rooted in a different
file everything will be ok. Objects (entries) in a TDirectory should not
hold their own file pointers, but should rather call
fDirectory->GetFile(). In this way you could move a whole TDirectory and
everything below it in one go.

Just a thought, cheers, Stefan

---Stefan Kluth---------------Lynen Fellow----------------|\--|\-------
- LBNL, MS 50A 2160 - phone: +1 510 495 2376 - |/ |/ -
- 1 Cyclotron Rd. - fax: +1 510 495 2957 - |\/\|\/\|' -
---Berkeley, CA94720, USA-----e-mail: SKluth@lbl.gov------|/\/|/\/|----