ROOT files

In ROOT you can save and read objects from ROOT files. With a ROOT file you can make the created objects “persistent”. When reading the ROOT file back, the object is reconstructed in the memory.

ROOT files also often contain tress ( TTree , see → Trees), a typical data container used for example by all LHC (Large Hadron Collider) experiments.

Working with ROOT files

A ROOT file, this is a TFile object, is like a UNIX file directory. It can contain directories and objects organized in unlimited number of levels. A ROOT file is stored in machine independent format (ASCII, IEEE floating point, Big Endian byte ordering).

Creating a ROOT file

  • Use the TFile constructor for creating a ROOT file. A ROOT file uses the .root extension.
   TFile *MyFile = new TFile("Event.root","OPTIONS");

The following options are available:

  • CREATE: Creates a ROOT file.

  • NEW: Same as CREATE.

  • RECREATE: Replaces the ROOT file.

  • UPDATE: Updates the ROOT file.

  • READ: Opens an existing ROOT file for reading.

Once a TFile object has been created, it becomes the default file for all I/O. This default is held in the global variable gFile (see → ROOT classes, data types and global variables), which can be updated at any time to change the default.

   gFile = MyFile;

Current directory

When you create a TFile object, it becomes the current directory. Therefore, the last ROOT file to be opened is always the current directory.
Check the current directory as follows:

   gDirectory->pwd()

   Rint:/

In this case, the current directory is the ROOT session (Rint).

When you create a TFile object, the ROOT file becomes the current directory.

   TFile f1("my.root");
   gDirectory->pwd()

   my.root:/

Checking whether a ROOT file is open

  • Use TFile::IsOpen() to check whether the ROOT file was successfully opened.

Note

You can also check whether the ROOT file is correctly opened by:

   TFile f("demo.root");
   if (f.IsZombie()) {
      cout << "Error opening file" << endl;
      exit(-1);
      } else {
      ...
   }

Writing ROOT files

You can save any object, for example canvases, histograms or trees, in a ROOT file.

To write objects to a ROOT file, the objects must be open.

Example

A copy of MyObject is written to the current directory of the current ROOT file with the named key MyObject_1:

   MyObject->Write("MyObject_1");

If MyObject does not inherit from TClass , you can use

   gDirectory->WriteObject(MyObject,"MyObject_1");

Example

This example creates 15 histograms, fills each histogram with 1000 entries from a Gaussian distribution, and writes them to a ROOT file.

{
   char name[10], title[20];

// Create an array of histograms.
   TObjArray Hlist(0);

// Create a pointer to a histogram.
   TH1F* h;

// Make and fill 15 histograms and add them to the object array.
   for (Int_t i = 0; i < 15; i++) {
      sprintf(name,"h%d",i);
      sprintf(title,"histo nr:%d",i);
      h = new TH1F(name,title,100,-4,4);
      Hlist.Add(h);
      h->FillRandom("gaus",1000);
   }

// Open a ROOT file and write the array to the ROOT file.
   TFile f("demo.root","RECREATE");
   Hlist.Write();

// Closing the ROOT file.
   f.Close();
}

The ROOT file is saved by default in the current working directory.

Closing a ROOT file

   MyFile->Close();

ROOT will automatically close any ROOT files still open when the session ends.

  • Use delete to delete the TFile object.
   delete MyFile;

Retrieving objects from a ROOT file

  • Use the GetObject() method to retrieve the objects from a ROOT file.

Example

From the ROOT file hsimple.root (see → First steps with ROOT), the histogram hpx;1 is retrieved.

   TFile f("hsimple.root");
   TH1F *hpx;
   f.GetObject("hpx;1",hpx);

//The retrieved histogram is drawn.
   hpx->Draw();

In detail, the following happens when executing GetObject():

  • The key with name hpx;1 is found in the list of keys.

  • A TBuffer object is created.

  • The buffer is read from the ROOT file.

  • An empty object is created by calling the default constructor for the class referenced in TKey .

  • The Streamer() method is called for this new object.

In case there is an object with multiple cycles, you can pick a particular cycle with a name like hpx; (for example hpx;2).

You can also directly access the keys, for example when the names of the objects contained in the ROOT file are not known or when a long series of objects needs to be read sequentially.

Example

This example illustrates how to loop over all keys of a ROOT file.

for (TObject* keyAsObj : *inputFile.GetListOfKeys()){
    auto key = dynamic_cast<TKey*>(keyAsObj);
    std::cout << "Key name: " << key->GetName() << " Type: " << key->GetClassName() << std::endl;
}

Crash while reading and writing the ROOT file

If ROOT is not properly terminated, the file directory may not be written at the end of the ROOT file. Next time this ROOT file is used, ROOT will automatically detect this abnormal termination and will recover the directory by scanning sequentially the list of keys in the ROOT file. If the ROOT file has been opened in UPDATE mode, the recovered directory will be automatically written to the ROOT file. This automatic recovery procedure is possible because of redundant information written to the ROOT file.
In case you write large trees (see also → Trees), you may have large buffers in memory. In case of a job crash, you may loose a lot of data. Therefore, it recommended to use the auto save method TTree::AutoSave.

Reading histograms from a ROOT file

  • Use the Get() method to read histograms from a ROOT file.

Example

   TFile *f = new TFile("histo.root");

   f->ls()

   TH1F * h1 = (TH1F*)f->Get("h1");
   h1->Draw();

Merging ROOT files with hadd

  • Use the hadd utility in $ROOTSYS/bin/hadd, to merge ROOT files:
   hadd result.root file1.root file2.root ... filen.root

File system operations

A TFile , this is ROOT file, behaves like UNIX file system. Therefore, you can perform the usual operations for a file system.

Example

// Create/open a ROOT file.
   TFile* f = TFile::Open("file.root", "NEW");

// Creating a directory.
   f->mkdir("dir");

// Changing the current working directory.
   f->cd("dir");

// Listing the contents of a ROOT file.
   f->ls();

ROOT command line tools

With the ROOT command line tools you can quickly inspect and modify the contents of ROOT files. There are ROOT command line tools for:

  • simple file operations
  • automating common operations performed on ROOT classes

File operations

  • rootls: Lists the content of a ROOT file.
  • rootcp: Copies objects stored in a ROOT file to another ROOT file.
  • rootrm: Deletes objects contained in a ROOT file.
  • rootmv: Moves objects stored in a ROOT file to another ROOT file.
  • rootmkdir: Creates a “directory” inside a ROOT file.

Example

On the system prompt, you can use the ROOT command line tool rootls to list the contents of a ROOT file.

$ rootls hsimple.root
hprof  hpx  hpxpy  ntuple

Operations on ROOT classes

  • rootbrowse: Opens a TBrowser directly with the contents of a ROOT file.
  • rooteventselector: Extracts a range of events of a tree contained in a ROOT file and put them as a new tree in another ROOT file.
  • rootprint: Plots objects in an image ROOT file.
  • rootslimtree: Copies trees with a subset of branches from source ROOT files.
  • genreflex: Generates dictionary sources and related ROOT pcm, starting from an header.
  • hadd: Adds histograms from a list of ROOT files and writes them to a target ROOT file.

Use the -h option to get more information on the available options for the specific ROOT command line tool.

ROOT Object Browser

With a TBrowser , this is the ROOT Object Browser, you can browse all ROOT objects within a ROOT file.

   root[0] TFile f("demo.root")
   root[1] TBrowser browser

The ROOT Object Browser is displayed.

Figure: ROOT Object Browser.

  • Click the ROOT file and the content of the ROOT file.

Figure: ROOT Object Browser displaying the content of a ROOT file.

Graphical objects are displayed in the Canvas_1 tab. Files that end with .C or .root are displayed in the Editor 1 tab.

Using folders

A TFolder is a collection of objects visible and expandable in the ROOT Object Browser. Folders have a name and a title. They are identified in the folder hierarchy by an “UNIX-like” naming convention. New folders can be added and removed to/from a folder.

Difference between TFolder and TDirector
A TFolder manages a hierarchy of objects in the memory. A TDirectory is doing that for a file.
You can save the TFolder structure to a directory in a ROOT file.

The base of all folders is the //root folder. It is visible at the top of the left panel in the ROOT Object Browser.

Figure: root folder in the ROOT Object Browser.

With folders you can reduce class dependencies and improve modularity. Each set of data has a producer class and one or many consumer classes. When using folders, the producer class places a pointer to the data into a folder, and the consumer class retrieves a reference to the folder. The consumer can access the objects in a folder by specifying the path name of the folder.

Creating a folder hierarchy

To create a folder hierarchy, you add a top folder of your hierarchy to //root. Then you add a folder to an existing folder with the TFolder::AddFolder() method. The AddFolder() method takes two parameters: the name and title of the folder to be added. It returns a pointer of the newly created folder.

The following example creates a folder hierarchy shown in the ROOT Object Browser.

Example

{
// Add the top folder of my hierarchy to //root.
   TFolder *aliroot=gROOT->GetRootFolder()->AddFolder("aliroot","aliroot top level folders");

// Add the hierarchy to the list of browsables
   gROOT->GetListOfBrowsables()->Add(aliroot,"aliroot");

// Create and add the constants folder.
   TFolder *constants=aliroot->AddFolder("Constants","Detector constants");

// Create and add the pdg folder to pdg.
   TFolder *pdg = constants->AddFolder("DatabasePDG","PDG database");

// Create and add the run folder.
   TFolder *run = aliroot->AddFolder("Run","Run dependent folders");

// Create and add the configuration folder to run.
   TFolder *configuration = run->AddFolder("Configuration","Run configuration");

// Create and add the run_mc folder.
   TFolder *run_mc = aliroot->AddFolder("RunMC","MonteCarlo run dependent folders");

// Create and add the configuration_mc folder to run_mc
   TFolder *configuration_mc = run_mc->AddFolder("Configuration","MonteCarlo run configuration");
}

Figure: Folder hierarchy in the ROOT Object Browser.

Reading data from a folder

The FindObjectAny() method analyzes the string passed as its argument and searches in the hierarchy until it finds an object or folder matching the name.

With FindObjectAny() you can give the full path name, or the name of the folder. If only the name of the folder is given, it will return the first instance of that name.

A string-based search is time consuming. If the retrieved object is used frequently or inside a loop, save a pointer to the object as a class data member.

By default, a folder does not own the object it contains. You can overwrite that with TFolder::SetOwner(). Once the folder is the owner of its contents, the contents are deleted when the folder is deleted.

Example

If a file myFile.root is added to the list of files, you can retrieve a pointer to the corresponding TFile object with the following statements:

   TFile *myFile = (TFile*)gROOT->FindObjectAny("/ROOTFiles/myFile.root");

//or...

   TFile *myFile = (TFile*)gROOT->FindObjectAny("myFile.root");

Viewing the contents of a ROOT file

TFile is a descendent of TDirectory , which means it behaves like a TDirectory. You can list the contents, print the name, and create subdirectories. In a ROOT session, you are always in a directory and the directory you are in is called the current directory and is stored in the global variable gDirectory (see → gDirectory).

Physical layout of a ROOT file

  • Use the TFile::Map() method to view the physical layout of a ROOT file.

The output prints the date/time, the start record address, the number of bytes in the record, the class name of the record and the compression factor.

Example

root[] f.Map()

20191010/122600    At:100     N=114    TFile
20191010/122600    At:214     N=429    TH1F           CX = 2.31
20191010/122600    At:643     N=424    TH1F           CX = 2.33
20191010/122600    At:1067    N=426    TH1F           CX = 2.32
20191010/122600    At:1493    N=425    TH1F           CX = 2.33
20191010/122600    At:1918    N=429    TH1F           CX = 2.31
20191010/122600    At:2347    N=424    TH1F           CX = 2.33
20191010/122600    At:2771    N=418    TH1F           CX = 2.37
20191010/122600    At:3189    N=428    TH1F           CX = 2.31
20191010/122600    At:3617    N=422    TH1F           CX = 2.34
20191010/122600    At:4039    N=421    TH1F           CX = 2.35
20191010/122600    At:4460    N=431    TH1F           CX = 2.30
20191010/122600    At:4891    N=424    TH1F           CX = 2.34
20191010/122600    At:5315    N=430    TH1F           CX = 2.31
20191010/122600    At:5745    N=426    TH1F           CX = 2.33
20191010/122600    At:6171    N=425    TH1F           CX = 2.34
20191010/122600    At:6596    N=3055   StreamerInfo   CX = 3.08
20191010/122600    At:9651    N=732    KeysList
20191010/122600    At:10383   N=53     FreeSegments
20191010/122600    At:10436   N=1      END

Logical contents of a ROOT file

ROOT provides not only sequential access to the content of a ROOT file, but also random or direct access.

TFile keeps a list of TKey objects, which is an index to the objects in the ROOT file.

The TKey class describes the record headers of objects in the ROOT file. With the GetListOfKeys() method you get the list of keys.

Example

Get the list of keys from the demo.root file and print them.

root[0] TFile f("demo.root")
root[1] f.GetListOfKeys()->Print()

TKey Name = h0,     Title = histo    nr:0,     Cycle = 1
TKey Name = h1,     Title = histo    nr:1,     Cycle = 1
TKey Name = h2,     Title = histo    nr:2,     Cycle = 1
TKey Name = h3,     Title = histo    nr:3,     Cycle = 1
TKey Name = h4,     Title = histo    nr:4,     Cycle = 1
TKey Name = h5,     Title = histo    nr:5,     Cycle = 1
TKey Name = h6,     Title = histo    nr:6,     Cycle = 1
TKey Name = h7,     Title = histo    nr:7,     Cycle = 1
TKey Name = h8,     Title = histo    nr:8,     Cycle = 1
TKey Name = h9,     Title = histo    nr:9,     Cycle = 1
TKey Name = h10,    Title = histo    nr:10,    Cycle = 1
TKey Name = h11,    Title = histo    nr:11,    Cycle = 1
TKey Name = h12,    Title = histo    nr:12,    Cycle = 1
TKey Name = h13,    Title = histo    nr:13,    Cycle = 1
TKey Name = h14,    Title = histo    nr:14,    Cycle = 1

Finding TKey objects

With the TFile::Get() method, you can find TKey objects.

Example

   root[] TH1F *h9 = (TH1F*)f.Get("h9");

The Get() method finds the TKey object with name h9.

Iterating over objects

Keys are available in a TList of TKey s. Therefore, you can iterate over the list of keys.

Example

The TKeys of the demo.root (see example → Creating a ROOT file) file are iterated.

{
   TFile f("demo.root");
   TIter next(f.GetListOfKeys());
   TKey *key;
   while ((key=(TKey*)next())) {
      printf("key: %s points to an object of class: %s at %dn", key->GetName(),
      key->GetClassName(),key->GetSeekKey());
   }
}

The output is of the iterate.C ROOT macro is:

root[] .x iterate.C

key: h0 points to an object of class: TH1F at 150
key: h1 points to an object of class: TH1F at 503
key: h2 points to an object of class: TH1F at 854
key: h3 points to an object of class: TH1F at 1194
key: h4 points to an object of class: TH1F at 1539
key: h5 points to an object of class: TH1F at 1882
key: h6 points to an object of class: TH1F at 2240
key: h7 points to an object of class: TH1F at 2582
key: h8 points to an object of class: TH1F at 2937
key: h9 points to an object of class: TH1F at 3293
key: h10 points to an object of class: TH1F at 3639
key: h11 points to an object of class: TH1F at 3986
key: h12 points to an object of class: TH1F at 4339
key: h13 points to an object of class: TH1F at 4694

Objects in memory and on disk

TFile::ls() lists with option -d the objects on disk and with option -m the objects in memory.
If no option is specified, both are listed, first the objects in memory, then the objects on disk.
The current directory is stored in the global variable gDirectory.

Example

root[] TFile *f = new TFile("hsimple.root");
root[] gDirectory->ls("-m")
TFile**         hsimple.root   Demo ROOT file with histograms
 TFile*         hsimple.root   Demo ROOT file with histograms

Example

This example lists the objects on disk in the current directory.

root[] gDirectory->ls("-d")
TFile**         hsimple.root   Demo ROOT file with histograms
 TFile*         hsimple.root   Demo ROOT file with histograms
  KEY: TH1F     hpx;1   This is the px distribution
  KEY: TH2F     hpxpy;1   py vs px
  KEY: TProfile hprof;1   Profile of pz versus px
  KEY: TNtuple  ntuple;1   Demo ntuple

To transfer an object from disk to memory, you have to use it explicitly.

Example

Drawing hproffrom the hsimple.root reads it from the ROOT file and creates an object in memory.

root[] hprof->Draw()
<TCanvas::MakeDefCanvas>: created default TCanvas with name c1

root[] f->ls()
TFile** hsimple.root
TFile* hsimple.root
OBJ: TProfile hprof Profile of pz versus px : 0
KEY: TH1F hpx;1 This is the px distribution
KEY: TH2F hpxpy;1 py vs px
KEY: TProfile hprof;1 Profile of pz versus px
KEY: TNtuple ntuple;1 Demo ntuple

The line beginning with OBJ indicates that an TProfile object, called hprof, has been added in memory to this directory. This new hprof object in memory is independent from the hprof object on disk. If you make changes to the hprof object in memory, they are not propagated to the hprof object on disk. A new version of the hprof object is only saved if you use the Write() method.

Streamers

When talking about “writing an object to a file”, what is actually meant is writing the current values of the data members. The most common way to do this is to decompose (also called serialize) the object into its data elements and then write them to disk. This decomposition is done by a Streamer. Each class that is to be stored in a ROOT file requires a Streamer, which decomposes the class and “streams” its members into a buffer.

Variables of composite data types such as classes, structures, and arrays can be decomposed in simple types such as longs, shorts, floats, and chars.

The methods of the class are not written to the ROOT file, it contains only the persistent data members. To decompose the parent classes, the Streamer calls the Streamer of the parent classes. It moves up the inheritance tree until it reaches an ancestor with no parent. To serialize the object data members, it calls their Streamers. These in turn move up their own inheritance tree and so on. The simple data elements are written directly to the buffer. Finally, the buffer contains all the simple data members of all the classes that make up that particular object. Data members that are references are never stored, it is always the responsibility of the object’s constructor to set them correctly.

Automatically generated streamers

A streamer typically calls on other Streamers: its parent’s streamers and data members. This architecture requires that all classes have Streamers, because eventually they will be called. To ensure that a class has a Streamer, rootcling automatically creates one in the ClassDef macro defined in $ROOTSYS/include/Rtypes.h. ClassDef defines several methods for each class, and one of them is the Streamer. The automatically generated streamer is complete and can be used as long as no customization is required.

The Event class is defined in $ROOTSYS/test/Event.h. It inherits from TObject .

Example

A simple example of a class with several data members.

   class Event : public TObject {
   private:
   TDirectory *fTransient;      //! Current directory.
   Float_t fPt;                 //! Transient value.
   char fType[20];
   Int_t fNtrack;
   Int_t fNseg;
   Int_t fNvertex;
   UInt_t fFlag;
   Float_t fTemperature;
   EventHeader fEvtHdr;         //|| Do no split.
   TClonesArray *fTracks;       //->
   TH1F *fH;                    //->
   Int_t fMeasures[10];
   Float_t fMatrix[4][4];
   Float_t *fClosestDistance;   //[fNvertex]

The Event class is added to the dictionary with rootcling.

rootcling -f EventDict.cxx -c Event.h EventLinkDef.h

The EventDict.cxx file contains the automatically generated Streamer for Event.

   void Event::Streamer(TBuffer &R__b){

// Stream an object of class Event.
   if (R__b.IsReading()) {
      Event::Class()->ReadBuffer(R__b, this);
      } else {
      Event::Class()->WriteBuffer(R__b, this);
         }
      }

When writing an Event object, TClass::WriteBuffer() is called. TClass::WriteBufferwrites the current version number of the Event class, and its contents into the buffer R__b. The Streamer calls TClass::ReadBuffer() when reading an Event object. The TClass::ReadBufferRead() method reads the information from buffer R__b into the Event object.

Transient data members

To prevent a data item from being written to the file, insert a ! as the first character in the comment (//). It tells ROOT not to store this data item in a ROOT file when saving the class.

Example

   class Event : public TObject {
   private:
   TDirectory *fTransient;       //! Current directory.
   Float_t fPt;                  //! Transient value
...

The pointer to objects

The string -> in the comment of the members *fH and *fTracks tells the automatic Streamer to assume that these point to valid objects and that the Streamer of the objects can be called, instead of the more expensive R__b << fH. Note that there is no check for the validity of the pointer value. In particular, if the pointer points, directly or indirectly, back to the current object, this leads to an infinite recursion and the abrupt end of the process.

Example

   TClonesArray *fTracks;       //->
   TH1F *fH;                    //->

Variable length array

When the Streamer finds a pointer to a simple type, it assumes it is an array. Somehow it needs to know how many elements are in the array in order to allocate enough space in the buffer and write out the appropriate number of elements. This is done in the class definition.

Example

   class Event : public TObject {
   private:
   char fType[20];
   Int_t fNtrack;
   Int_t fNseg;
   Int_t fNvertex;
   ...
   Float_t *fClosestDistance;         //[fNvertex]

The fClosestDistance array is defined as a pointer of floating point numbers. A comment mark (//), and the number in square brackets tell the Streamer the length of the array for this object. In general the syntax is:

<simple type> *<name>//[<length>]

The length cannot be an expression. If a variable is used, it must be an integer data element of the class. It must be defined before it is used or in a base class.

The same notation applies to variable length arrays of objects and variable length arrays of pointers to objects.

   MyObject *obj;        //[fNojbs]
   MyObject **objs;      //[fDatas]

Double32_t

Mathematical operations very often require double precision, but when storing, single precision is usually sufficient. For this purpose the typedef Double32_t is supported, which is stored in memory as double and on disk as float or integer. The actual size on disk (before compression) is determined by the parameter next to the data element declaration.

Example

   Double32_t m_data;    //[min,max<,nbits>]

If the comment is absent or does not contain min, max, nbits, the member is saved as a float.

If min and max are present, they are saved with 32 bits precision. min and max can be explicit values or expressions of values known to rootlcing (for example pi).

If nbits is present, the member is saved as integer with nbits bits precision. For more details, see the I/O-tutorials double32.C.

Preventing splitting

If you want to prevent a data item from being split when you write it to a tree, add || directly after the comment. This is only useful for object data members.

Example

   EventHeader fEvtHdr;        //|| Do not split the header.

Streamers with special additions

Usually, a Streamer is generated by rootcling. However, you can also create your own Streamer. There are two reasons why you should create your own streamer:

  1. If you have a non-persistent data item that you want to initialize to a value depending on the data items you read.
  2. If you need to handle or schema evolution yourself.

Example

First, you need to tell rootcling not to build a Streamer. The input to the rootcling command (in the makefile) is a list of classes in a LinkDef.h file. For example, the list of classes for Event is listed in $ROOTSYS/test/EventLinkDef.h. - at the end of the class name indicates rootcling not to generate a Streamer. In this example can see that the Event class is the only one for which rootcling is instructed not to generate a Streamer.

#ifdef __ROOTCLING__

#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link C++ class EventHeader+;
#pragma link C++ class Event-;
#pragma link C++ class HistogramManager+;
#pragma link C++ class Track+;
#endif
#pragma link C++ class EventHeader+;

The + sign indicates rootcling to use the Streamer system.

The following is an example of a customized Streamer for Event. The Streamer takes a
TBuffer as a parameter, and first checks to see if this is a case of reading or writing the buffer.

Example

   void Event::Streamer(TBuffer &R__b) {
   if (R__b.IsReading()) {
   Event::Class()->ReadBuffer(R__b, this);
   fTransient = gDirectory; //save current directory
   fPt= TMath::Sqrt(fPx*fPx + fPy*fPy + fPz*fPz);
   } else {
      Event::Class()->WriteBuffer(R__b, this);
      }
   }

Writing objects

A Streamer breaks the objects into data members and writes them to a buffer. It does not write the buffer to a file, but simply fills a buffer with bytes representing the object. This allows, for example, to write the buffer to a file. For example, you can write it to a socket to send it over the network.

A buffer is written to a file by loading the dictionary for a class before an object of that type can be stored.

The TObject::Write() method does the following:

  • Creates a TKey object in the current directory.
  • Creates a TBuffer object, which is part of the newly created TKey .
  • Fills the TBuffer with a call to the class::Streamer method.
  • Creates a second buffer for compression, if needed.
  • Reserves space by scanning the TFree list. At this point, the size of the buffer is known.
  • Writes the buffer to the file.
  • Releases the TBuffer part of the key.

This means that the TObject::Write() calls the Streamer method of the class to build the buffer. The buffer is in the key and the key is written to disk. Once written to disk, the memory consumed by the buffer part is released. The key part of the TKey is kept. The key consumes about 60 bytes, whereas the buffer, since it contains the object data, can be very large.

Ignoring object Streamers

A class can ignore the TObject Streamer with the MyClass->Class::IgnoreObjectStreamer() method. When the kIgnoreTObjectStreamerbit class is set (by calling the IgnoreTObjectStreamer() method), the automatically generated Streamer does not call TObject::Streamer, and the TObject part of the class is not streamed to the file. This is useful in case you do not use the TObject fBits and fUniqueIDdata members. You gain space on the file, and you do not loose functionality if you do not use the fBits and fUniqueID.

Streaming a TClonesArray

When writing a TClonesArray , it bypasses by default the Streamer of the member class and uses a more efficient internal mechanism to write the members to the file.

You can override the default and specify that the member class Streamer is used by setting the TClonesArray::BypassStreamer bit to false:

   TClonesArray *fTracks;
   fTracks->BypassStreamer(kFALSE);             // Use the member Streamer.

When the kBypassStreamer bit is set, the automatically generated Streamer can call directly the TClass::WriteBuffer method. Bypassing the Streamer improves the performance when writing or reading the objects in the TClonesArray .

However, the drawback is when a TClonesArray is written with split=0 bypassing the Streamer, the StreamerInfo of the class in the array being optimized, one cannot later use the TClonesArray . with split > 0.

For example, there is a problem with the following scenario: a class Foo has a TClonesArray of Bar objects the Foo object is written with split=0 to tree T1. In this case the StreamerInfo for the class Bar is created in optimized mode in such a way that data members of the same type are written as an array improving the I/O performance. In a new program, T1 is read and a new tree T2 is created with the object Foo in split > 1.

When the T2branch is created, the StreamerInfo for the class Bar is created with no optimization (mandatory for the split mode). The optimized Bar StreamerInfo is going to be used to read the TClonesArray in T1. The result are Bar objects with data member values not in the right sequence. The solution to this problem is to call BypassStreamer(kFALSE) for the % include ref class=”TClonesArray” %}. In this case, the normal Bar::Streamer function is called. The Bar::Streamer function works independently if the Bar StreamerInfo has been generated in optimized mode or not.

Remotely accessing a ROOT file

You can remotely access ROOT files on the base of the protocol URL.

You can read and write a ROOT file over the net by using the TFile::Open() method.

Example

Simple session:

root[] TFile *f1 = TFile::Open("local/file.root","update")
root[] TFile *f2 = TFile::Open("root://my.server.org/data/file.root","new")
root[] TFile *f3 = TFile::Open("https://root.cern/files/hsimple.root")

ls() lists what is in the ROOT file.

root[] f3.ls()
TDavixFile**    https://root.cern/files/hsimple.root
 TDavixFile*    https://root.cern/files/hsimple.root
  KEY: TH1F     hpx;1 This is the px distribution
  KEY: TH2F     hpxpy;1 py vs px
  KEY: TProfile hprof;1 Profile of pz versus px
  KEY: TNtuple  ntuple;1 Demo ntuple

XML interface

You can save a canvas to an XML file, that is a file.xml file instead of a file.root. XML files have no advantages over the normal ROOT files, except that the information in these files can be edited with a normal text editor.

XML files should only be used for small amounts of data, typically histogram files, images, geometries, calibrations. The XML file is created in memory before it is stored on disk. As for normal ROOT files, XML files use the same I/O mechanism that the ROOT/Cling dictionary uses. Any class that has a dictionary can be stored in XML format. XML files do not support subdirectories or trees.

To create an XML file, specify a filename with an .xml extension when calling TFile::Open(). TFile::Open() recognizes that you are trying to open an XML file and returns a TXMLFile object. When a XML file is open in write mode, you can use TObject::Write() to write an object into the XML file.

Example

// Example of a session saving a histogram to a XML file.
   TFile *f = TFile::Open("Example.xml","recreate");
   TH1F *h = new TH1F("h","test",1000,-2,2)
   h->FillRandom("gaus");
   h->Write();
  delete f;

// Example of a session saving a histogram to a XML file.
   TFile *f = TFile::Open("Example.xml");
   TH1F *h = (TH1F*)f->Get("h");
   h->Draw();
   canvas->Print("Example.xml");