TFileIter.cxx

Go to the documentation of this file.
00001 // @(#)root/table:$Id: TFileIter.cxx 35878 2010-09-30 08:28:57Z brun $
00002 // Author: Valery Fine(fine@bnl.gov)   01/03/2001
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
00006  * Copyright (C) 2001 [BNL] Brookhaven National Laboratory.              *
00007  * All rights reserved.                                                  *
00008  *                                                                       *
00009  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00010  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00011  *************************************************************************/
00012 
00013 ///////////////////////////////////////////////////////////////////////////
00014 //                                                                       //
00015 // Class to iterate (read / write ) the events written to TFile.         //
00016 // The event is supposed to assign an unique ID in form of               //
00017 //                                                                       //
00018 //  TKey <event Id> ::= eventName "." run_number "." event_number        //
00019 //                                                                       //
00020 // and stored as the TKey name of the object written                     //
00021 //                                                                       //
00022 //        ///////        //////////      ////////        ///////     //////
00023 //
00024 // void TesTFileIter(){
00025 // // This macros tests the various methods of TFileIter class.
00026 //   gSystem->Load("libTable");
00027 //
00028 //   //First create simple ROOT file
00029 //   TDataSet *ds = new TDataSet("event");
00030 //   TObject *nextObject = 0;
00031 //   TRandom run;
00032 //   TRandom event;
00033 //   {
00034 //     TFileIter outSet("test.root","RECREATE");
00035 //     UInt_t totalEvent = 10;
00036 //     UInt_t runNumber  = 20010301;
00037 //     Int_t i=0;
00038 //     Int_t j=0;
00039 //     for (;j < 10;j++) {
00040 //       for (i = 1;i<totalEvent;i++) {
00041 //         outSet.NextEventPut(ds,UInt_t(i),UInt_t(runNumber+j+10*run.Rndm()-5));
00042 //       }
00043 //     }
00044 //   }
00045 //   printf(" ----------------------> TFile has been created <--------------------\n");
00046 //   TFile *f = new TFile("test.root");
00047 //   TFileIter readObj(f);
00048 //   // the number of the object available directly from "MyDataSet.root"
00049 //   Int_t size = readObj.TotalKeys();
00050 //   printf(" The total number of the objects: %d\n",size);
00051 //
00052 //   //-----------------------------------------------------------------------
00053 //   // Loop over all objects, read them in to memory one by one
00054 //
00055 //   printf(" -- > Loop over all objects, read them in to memory one by one < -- \n");
00056 //   for( readObj = 0; int(readObj) < size; ++readObj){
00057 //       nextObject = *readObj;
00058 //       printf(" %d bytes of the object \"%s\" of class \"%s\" written with TKey \"%s\"  has been read from file\n"
00059 //                ,readObj.GetObjlen()
00060 //                ,nextObject->GetName()
00061 //                ,nextObject->IsA()->GetName()
00062 //                ,(const char *)readObj
00063 //             );
00064 //       delete nextObject;
00065 //  }
00066 // //-----------------------------------------------------------------------
00067 // //  Now loop over all objects in inverse order
00068 //  printf(" -- > Now loop over all objects in inverse order < -- \n");
00069 //  for( readObj = size-1; (int)readObj >= 0; --readObj)
00070 //  {
00071 //       nextObject = *readObj;
00072 //       if (nextObject) {
00073 //          printf(" Object \"%s\" of class \"%s\" written with TKey \"%s\"  has been read from file\n"
00074 //                 ,nextObject->GetName()
00075 //                 , nextObject->IsA()->GetName()
00076 //                 ,(const char *)readObj
00077 //                );
00078 //         delete nextObject;
00079 //      } else {
00080 //        printf("Error reading file by index\n");
00081 //      }
00082 //  }
00083 // //-----------------------------------------------------------------------
00084 // // Loop over the objects starting from the object with the key name "event.02.01"
00085 //   printf(" -- > Loop over the objects starting from the object with the key name \"event.02.01\" < -- \n");
00086 //   for( readObj = "event.02.01"; (const char *)readObj != 0; ++readObj){
00087 //       nextObject = *readObj;
00088 //       printf(" Object \"%s\" of class \"%s\" written with Tkey \"%s\"  has been read from file\n"
00089 //               , nextObject->GetName()
00090 //               , nextObject->IsA()->GetName()
00091 //               , (const char *)readObj
00092 //             );
00093 //       delete nextObject;
00094 //   }
00095 //
00096 //   printf(" -- > Loop over the objects starting from the 86-th object" < -- \n");
00097 //   for( readObj = (const char *)(readObj = 86); (const char *)readObj != 0; ++readObj){
00098 //       nextObject = *readObj;
00099 //       printf(" Object \"%s\" of class \"%s\" written with Tkey \"%s\"  has been read from file\n"
00100 //               , nextObject->GetName()
00101 //               , nextObject->IsA()->GetName()
00102 //               , (const char *)readObj
00103 //             );
00104 //       delete nextObject;
00105 //   }
00106 //
00107 // }
00108 //-----------------------------------------------------------------------
00109 ///////////////////////////////////////////////////////////////////////////
00110 
00111 
00112 #include <assert.h>
00113 
00114 #include "TEnv.h"
00115 #include "TSystem.h"
00116 #include "TFile.h"
00117 #include "TKey.h"
00118 
00119 #include "TFileIter.h"
00120 #include "TDsKey.h"
00121 
00122 ClassImp(TFileIter)
00123 
00124 //__________________________________________________________________________
00125 TFileIter::TFileIter(TFile *file) : fFileBackUp(0),fDirectoryBackUp(0), fNestedIterator(0)
00126          , fRootFile(file)
00127          , fEventName("event"), fRunNumber(UInt_t(-1)),fEventNumber(UInt_t(-1))
00128          , fCursorPosition(-1),  fOwnTFile(kFALSE)
00129 { 
00130    // Create iterator over all objects from the TFile provided
00131    Initialize(); 
00132 }
00133 
00134 //__________________________________________________________________________
00135 TFileIter::TFileIter(TDirectory *directory) :  fFileBackUp(0),fDirectoryBackUp(0),fNestedIterator(0)
00136          , fRootFile(directory)
00137          , fEventName("event"), fRunNumber(UInt_t(-1)),fEventNumber(UInt_t(-1))
00138          , fCursorPosition(-1),  fOwnTFile(kFALSE)
00139 { 
00140    // Create iterator over all objects from the TDirectory provided
00141    Initialize(); 
00142 }
00143 //__________________________________________________________________________
00144 TFileIter::TFileIter(const char *name, Option_t *option, const char *ftitle
00145                      , Int_t compress, Int_t /*netopt*/) : fFileBackUp(0),fDirectoryBackUp(0),fNestedIterator(0)
00146                                                          ,fRootFile(0)
00147                                                          ,fEventName("event"), fRunNumber(UInt_t(-1)) ,fEventNumber(UInt_t(-1))
00148                                                          ,fCursorPosition(-1), fOwnTFile(kFALSE)
00149 {
00150    // Open ROOT TFile by the name provided;
00151    // This TFile is to be deleted by the TFileIter alone
00152    if (name && name[0]) {
00153       fOwnTFile = kTRUE;
00154       // Map a special file system to rfio
00155       //   /hpss/in2p3.fr/group/atlas/cppm/data/genz
00156       //   #setenv HPSSIN bnlhpss:/home/atlasgen/evgen
00157       // #example for castor:   /castor/cern.ch/user/p/paniccia/evgen
00158       fRootFile = TFile::Open(MapName(name),option,ftitle,compress);
00159       Initialize();
00160    }
00161 }
00162 
00163 //__________________________________________________________________________
00164 TFileIter::TFileIter(const TFileIter &dst) : TListIter()
00165           ,fFileBackUp(0),  fDirectoryBackUp(0), fNestedIterator(0)
00166           ,fRootFile(dst.fRootFile),fEventName(dst.fEventName), fRunNumber(dst.fRunNumber)
00167           ,fEventNumber(dst.fRunNumber),
00168            fCursorPosition(-1),  fOwnTFile(dst.fOwnTFile)
00169 {
00170    // Copy ctor can be used with the "read only" files only.
00171    //the next statement is illegal, spotted by coverity "Dereferencing pointer "this->fRootFile". (Deref happens because this is a virtual function call.)
00172    //assert(!fRootFile->IsWritable());
00173    if (fRootFile && fOwnTFile) {
00174       // Reopen the file
00175       if (fRootFile->InheritsFrom(TFile::Class())) 
00176       {
00177          TFile *thisFile = (TFile *)fRootFile;
00178          fRootFile = TFile::Open(MapName(fRootFile->GetName())
00179             ,fRootFile->GetOption()
00180             ,fRootFile->GetTitle()
00181             ,thisFile->GetCompressionLevel());
00182       }
00183    }
00184 
00185    Initialize();
00186    // Adjust this iterator position
00187    SkipObjects(dst.fCursorPosition);
00188 }
00189 //__________________________________________________________________________
00190 TFileIter::~TFileIter()
00191 {
00192    // TFileIter dtor
00193    TFileIter *deleteit = fNestedIterator; fNestedIterator = 0;
00194    delete deleteit;
00195    if (fRootFile && fOwnTFile ) {  // delete own TFile if any
00196       if (fRootFile->IsWritable()) fRootFile->Write();
00197       fRootFile->Close();
00198       delete fRootFile;
00199       fRootFile = 0;
00200    }
00201 }
00202 
00203 //__________________________________________________________________________
00204 void TFileIter::Initialize()
00205 {
00206    //to be documented
00207    if (fRootFile) {
00208       fDirection =  kIterForward;
00209       if (IsOpen()) Reset();
00210       else  {
00211          if (fRootFile && fOwnTFile ) delete fRootFile;
00212          fRootFile = 0;
00213       }
00214    }
00215 }
00216 //__________________________________________________________________________
00217 Bool_t  TFileIter::IsOpen() const
00218 {
00219    // Check whether the associated ROOT TFile was open
00220    // and TFile object is healthy.
00221 
00222    Bool_t iOpen = kFALSE;
00223    if (fRootFile && !fRootFile->IsZombie() ) {
00224       iOpen = kTRUE;
00225       if (fRootFile->InheritsFrom(TFile::Class()) && !((TFile*)fRootFile)->IsOpen()) 
00226          iOpen = kFALSE;
00227    }
00228    return iOpen;
00229 }
00230 
00231 //__________________________________________________________________________
00232 TKey *TFileIter::GetCurrentKey() const
00233 {
00234   // return the pointer to the current TKey
00235    
00236    return ((TFileIter*)this)->SkipObjects(0);
00237 }
00238 //__________________________________________________________________________
00239 Int_t TFileIter::GetDepth() const
00240 {
00241    // return the current number of the nested subdirectroies;
00242    //      = 0 - means there is no subdirectories
00243    return fNestedIterator ? fNestedIterator->GetDepth()+1 : 0;
00244 }
00245 
00246 //__________________________________________________________________________
00247 const char *TFileIter::GetKeyName() const
00248 {
00249    // return the name of the current TKey
00250    const char *name = 0;
00251    TKey *key  = GetCurrentKey();
00252    if (key) name = key->GetName();
00253    return name;
00254 }
00255 //__________________________________________________________________________
00256 TObject *TFileIter::GetObject() const
00257 {
00258   // read the object from TFile defined by the current TKey
00259   //
00260   // ATTENTION:  memory leak danger !!!
00261   // ---------
00262   // This method does create a new object and it is the end-user
00263   // code responsibility to take care about this object
00264   // to avoid memory leak.
00265   //
00266    return ReadObj(GetCurrentKey());
00267 }
00268 //__________________________________________________________________________
00269 Int_t TFileIter::GetObjlen() const
00270 {
00271    // Returns the uncompressed length of the current object
00272    Int_t lenObj = 0;
00273    TKey *key = GetCurrentKey();
00274    if (key) lenObj = ((TKey *)key)->GetObjlen();
00275    return lenObj;
00276 }
00277 //__________________________________________________________________________
00278 Int_t TFileIter::TotalKeys() const
00279 {
00280   // The total number of the TKey keys in the current TDirectory only
00281   // Usually this means the total number of different objects
00282   // those can be read one by one.
00283   // It does NOT count the nested sub-TDirectory. 
00284   // It is too costly and it can be abused.
00285    
00286    Int_t size = 0;
00287    if(fList) size +=  fList->GetSize();
00288    return size;
00289 }
00290 //__________________________________________________________________________
00291 TObject *TFileIter::Next(Int_t  nSkip)
00292 {
00293   // return the pointer to the object defined by next TKey
00294   // This method is not recommended. It was done for the sake
00295   // of the compatibility with TListIter
00296 
00297    SkipObjects(nSkip);
00298    return GetObject();
00299 }
00300 
00301 //__________________________________________________________________________
00302 void TFileIter::PurgeKeys(TList *listOfKeys) 
00303 {
00304    // Remove the TKey duplication,
00305    // leave the keys with highest cycle number only
00306    // Sort if first
00307 
00308    assert(listOfKeys);
00309    listOfKeys->Sort();
00310    TObjLink *lnk   = listOfKeys->FirstLink();
00311    while(lnk) {
00312       TKey *key = (TKey *)lnk->GetObject();
00313       Short_t cycle = key->GetCycle(); 
00314       const char *keyName = key->GetName();
00315       // Check next object
00316       lnk = lnk->Next();
00317       if (lnk) {
00318          TKey *nextkey = 0;
00319          TObjLink *lnkThis = lnk;
00320          while (     lnk
00321              &&   (nextkey = (TKey *)lnk->GetObject()) 
00322              &&  !strcmp(nextkey->GetName(), keyName) 
00323             ) {
00324             // compare the cycles
00325             Short_t nextCycle = nextkey->GetCycle() ;
00326             //printf(" TFileIter::PurgeKeys found new cycle %s :%d : %d\n",
00327             //      keyName,cycle ,nextCycle);
00328             assert(cycle != nextCycle);
00329             TObjLink *lnkNext = lnk->Next();
00330             if (cycle > nextCycle ) { 
00331                delete listOfKeys->Remove(lnk);
00332             } else {
00333                delete listOfKeys->Remove(lnkThis);
00334                cycle   = nextCycle;
00335                lnkThis = lnk;
00336             }
00337             lnk = lnkNext;
00338          }
00339       }
00340    }
00341 }
00342 
00343 //__________________________________________________________________________
00344 void TFileIter::Reset()
00345 {
00346    // Reset the status of the iterator
00347    if (fNestedIterator) { 
00348       TFileIter *it = fNestedIterator; 
00349       fNestedIterator=0;
00350       delete it;
00351    }
00352    TListIter::Reset();
00353    if (!fRootFile->IsWritable()) {
00354       TList *listOfKeys = fRootFile->GetListOfKeys();
00355       if (listOfKeys) {
00356          if (!listOfKeys->IsSorted()) PurgeKeys(listOfKeys);
00357          fList = listOfKeys;
00358          if (fDirection == kIterForward) {
00359             fCursorPosition = 0;
00360             fCurCursor = fList->FirstLink();
00361             if (fCurCursor) fCursor = fCurCursor->Next();
00362          } else {
00363             fCursorPosition = fList->GetSize()-1;
00364             fCurCursor = fList->LastLink();
00365             if (fCurCursor) fCursor = fCurCursor->Prev();
00366          }
00367       }
00368    }
00369 }
00370 //__________________________________________________________________________
00371 void TFileIter::SetCursorPosition(const char *keyNameToFind)
00372 {
00373    // Find the key by the name provided
00374    Reset();
00375    while( (*this != keyNameToFind) && SkipObjects() ) {;}
00376 }
00377 //__________________________________________________________________________
00378 TKey *TFileIter::SkipObjects(Int_t  nSkip)
00379 {
00380  //
00381  // Returns the TKey pointer to the nSkip TKey object from the current one
00382  // nSkip = 0; the state of the iterator is not changed
00383  //
00384  // nSkip > 0; iterator skips nSkip objects in the container.
00385  //            the direction of the iteration is
00386  //            sign(nSkip)*kIterForward
00387  //
00388  // Returns: TKey that can be used to fetch the object from the TDirectory
00389  //
00390    TKey *nextObject  = fNestedIterator ? fNestedIterator->SkipObjects(nSkip): 0;
00391    if (!nextObject) {
00392       if (fNestedIterator) {
00393          TFileIter *it = fNestedIterator;
00394          fNestedIterator = 0;
00395          delete it;
00396       }
00397       Int_t collectionSize = 0;
00398       if (fList && (collectionSize = fList->GetSize())  ) {
00399          if (fDirection !=kIterForward) nSkip = -nSkip;
00400          Int_t newPos = fCursorPosition + nSkip;
00401          if (0 <= newPos && newPos < collectionSize) {
00402             do {
00403                if (fCursorPosition < newPos) {
00404                   fCursorPosition++;
00405                   fCurCursor = fCursor;
00406                   fCursor    = fCursor->Next();
00407                } else if (fCursorPosition > newPos) {
00408                   fCursorPosition--;
00409                   fCurCursor = fCursor;
00410                   fCursor    = fCursor->Prev();
00411                }
00412             } while (fCursorPosition != newPos);
00413             if (fCurCursor) nextObject = dynamic_cast<TKey *>(fCurCursor->GetObject());
00414          } else  {
00415             fCurCursor = fCursor = 0;
00416             if (newPos < 0) {
00417                fCursorPosition = -1;
00418                if (fList) fCursor = fList->FirstLink();
00419             } else  {
00420                fCursorPosition = collectionSize;
00421                if (fList) fCursor = fList->LastLink();
00422             }
00423          }
00424       }
00425    }
00426    return nextObject;
00427 }
00428 //__________________________________________________________________________
00429 TKey *TFileIter::NextEventKey(UInt_t eventNumber, UInt_t runNumber, const char *name)
00430 {
00431 
00432    // Return the key that name matches the "event" . "run number" . "event number" schema
00433 
00434    Bool_t reset = kFALSE;
00435    if (name && name[0] && name[0] != '*') { if (fEventName > name) reset = kTRUE; fEventName   = name; }
00436    if (runNumber   !=UInt_t(-1) ) { if (fRunNumber > runNumber)     reset = kTRUE; fRunNumber   = runNumber;}
00437    if (eventNumber !=UInt_t(-1) ) { if (fEventNumber > eventNumber) reset = kTRUE; fEventNumber = eventNumber;}
00438 
00439    if (reset) Reset();
00440    //   TIter &nextKey = *fKeysIterator;
00441    TKey *key = 0;
00442    TDsKey thisKey;
00443    while ( (key = SkipObjects()) ) {
00444       if (fDirection==kIterForward) fCursorPosition++;
00445       else                          fCursorPosition--;
00446       if ( name && name[0] != '*') {
00447          thisKey.SetKey(key->GetName());
00448          if (thisKey.GetName() < name)  continue;
00449          if (thisKey.GetName() > name) { key = 0; break; }
00450       }
00451       // Check "run number"
00452       if (runNumber != UInt_t(-1)) {
00453          UInt_t thisRunNumber = thisKey.RunNumber();
00454          if (thisRunNumber < runNumber) continue;
00455          if (thisRunNumber < runNumber) { key = 0; break; }
00456       }
00457       // Check "event number"
00458       if (eventNumber != UInt_t(-1)) {
00459          UInt_t thisEventNumber = thisKey.EventNumber();
00460          if (thisEventNumber < eventNumber) continue;
00461          if (thisEventNumber > eventNumber) {key = 0; break; }
00462       }
00463       break;
00464    }
00465    return key;
00466 }
00467 //__________________________________________________________________________
00468 TObject *TFileIter::NextEventGet(UInt_t eventNumber, UInt_t runNumber, const char *name)
00469 {
00470   // reads, creates and returns the object by TKey name that matches
00471   // the "name" ."runNumber" ." eventNumber" schema
00472   // Attention: This method does create a new TObject and it is the user
00473   // code responsibility to take care (delete) this object to avoid
00474   // memory leak.
00475 
00476    return ReadObj(NextEventKey(eventNumber,runNumber,name));
00477 }
00478 
00479 //__________________________________________________________________________
00480 TObject *TFileIter::ReadObj(const TKey *key)  const
00481 {
00482    //Read the next TObject from for the TDirectory by TKey provided
00483    TObject *obj = 0;
00484    if (fNestedIterator) obj = fNestedIterator->ReadObj(key);
00485    else if (key)  {
00486       obj = ((TKey *)key)->ReadObj();
00487       if (obj && obj->InheritsFrom(TDirectory::Class()) ) 
00488       {
00489          // create the next iteration level.
00490          assert(!fNestedIterator);
00491          ((TFileIter*)this)->fNestedIterator = new TFileIter((TDirectory *)obj);
00492          // FIXME:  needs to set  fDirection if needed 02/11/2007 vf
00493       }
00494    }
00495    return obj;
00496 }
00497 
00498 //__________________________________________________________________________
00499 Int_t  TFileIter::NextEventPut(TObject *obj, UInt_t eventNum,  UInt_t runNumber
00500                               , const char *name)
00501 {
00502    // Create a special TKey name with obj provided and write it out.
00503 
00504    Int_t wBytes = 0;
00505    if (obj && IsOpen() && fRootFile->IsWritable()) {
00506       TDsKey thisKey(runNumber,eventNum);
00507       if (name && name[0])
00508          thisKey.SetName(name);
00509       else
00510          thisKey.SetName(obj->GetName());
00511 
00512       if (fRootFile != gDirectory) {
00513          SaveFileScope();
00514          fRootFile->cd();
00515       }
00516       wBytes = obj->Write(thisKey.GetKey());
00517       if (fRootFile->InheritsFrom(TFile::Class())) ((TFile*)fRootFile)->Flush();
00518       if (fRootFile != gDirectory)     RestoreFileScope();
00519    }
00520    return wBytes;
00521 }
00522 //__________________________________________________________________________
00523 TString TFileIter::MapName(const char *name, const char *localSystemKey,const char *mountedFileSystemKey)
00524 {
00525    // --------------------------------------------------------------------------------------
00526    // MapName(const char *name, const char *localSystemKey,const char *mountedFileSystemKey)
00527    // --------------------------------------------------------------------------------------
00528    // Substitute the logical name with the real one if any
00529    // 1. add a line into system.rootrc or ~/.rootrc or ./.rootrc
00530    //
00531    //  TFileIter.ForeignFileMap  mapFile // the name of the file
00532                                          // to map the local name
00533                                          // to the global file service
00534    //
00535    //  If this line is omitted then TFileIter class seeks for
00536    //  the default mapping file in the current directory "io.config"
00537 
00538    // 2. If the "io.config" file found then it defines the mapping as follows:
00539    //
00540    //  TFileIter.LocalFileSystem   /castor
00541    //  TFileIter.MountedFileSystem rfio:/castor
00542 
00543    // If "io.config" doesn't exist then no mapping is to be performed
00544    // and all file names are treated "as is"
00545 
00546    if ( !localSystemKey)       localSystemKey       = GetLocalFileNameKey();
00547    if ( !mountedFileSystemKey) mountedFileSystemKey = GetForeignFileSystemKey();
00548    TString newName = name;
00549    TString fileMap = gEnv->GetValue(GetResourceName(),GetDefaultMapFileName());
00550    const char *localName    = 0;
00551    const char *foreignName  = 0;
00552    if ( gSystem->AccessPathName(fileMap) == 0 ){
00553       TEnv myMapResource(fileMap);
00554       localName    = myMapResource.Defined(localSystemKey) ?
00555                                     myMapResource.GetValue(localSystemKey,"") : 0;
00556       foreignName  = myMapResource.Defined(mountedFileSystemKey) ?
00557                                     myMapResource.GetValue(mountedFileSystemKey,""):0;
00558    } else {
00559       localName    = "/castor";      // This is the default CERN name
00560       foreignName  = "rfio:/castor"; // and it needs "RFIO"
00561    }
00562    if (localName && localName[0]
00563                  && foreignName
00564                  && foreignName[0]
00565                  && newName.BeginsWith(localName) )
00566       newName.Replace(0,strlen(localName),foreignName);
00567    return newName;
00568 }

Generated on Tue Jul 5 14:45:04 2011 for ROOT_528-00b_version by  doxygen 1.5.1