Re: moving a TDirectory from one TFile to another

From: stefan kluth (skluth@mh1.lbl.gov)
Date: Fri Dec 04 1998 - 20:51:33 MET


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------|/\/|/\/|----



This archive was generated by hypermail 2b29 : Tue Jan 04 2000 - 00:34:40 MET