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.
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
constructor for creating a ROOT file. A ROOT file uses the
The following options are available:
CREATE: Creates a ROOT file.
NEW: Same as
RECREATE: Replaces the ROOT file.
UPDATE: Updates the ROOT file.
READ: Opens an existing ROOT file for reading.
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.
When you create a
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:
In this case, the current directory is the ROOT session (
When you create a TFile object, the ROOT file becomes the current directory.
Checking whether a ROOT file is open
- Use TFile::IsOpen() to check whether the ROOT file was successfully opened.
You can also check whether the ROOT file is correctly opened by:
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.
- Use TFile::Write() to write objects to a ROOT file.
A copy of
MyObject is written to the current directory of the current ROOT file with the named key
MyObject does not inherit from
, you can use
This example creates 15 histograms, fills each histogram with 1000 entries from a Gaussian distribution, and writes them to a ROOT file.
The ROOT file is saved by default in the current working directory.
Closing a ROOT file
- Use TFile::Close() to close a ROOT file:
ROOT will automatically close any ROOT files still open when the session ends.
deleteto delete the TFile object.
Retrieving objects from a ROOT file
- Use the
GetObject()method to retrieve the objects from a ROOT file.
From the ROOT file
hsimple.root (see → First steps with ROOT), the histogram
hpx;1 is retrieved.
In detail, the following happens when executing
The key with name
hpx;1is 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
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.
This example illustrates how to loop over all keys of a ROOT file.
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.
Merging ROOT files with hadd
- Use the
$ROOTSYS/bin/hadd, to merge ROOT files:
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.
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
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.
On the system prompt, you can use the ROOT command line tool
rootls to list the contents of a ROOT file.
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.
-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.
- Create a TBrowser object:
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
.root are displayed in the
Editor 1 tab.
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.
Figure: Folder hierarchy in the ROOT Object Browser.
Reading data from a folder
- Use the TROOT::FindObjectAny() method to search for a folder or an object in a folder.
FindObjectAny() method analyzes the string passed as its argument and searches in the hierarchy until it finds an object or folder matching the name.
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.
If a file
myFile.root is added to the list of files, you can retrieve a pointer to the corresponding
object with the following statements:
Viewing the contents of a ROOT file
is a descendent of
, 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.
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.
TKey class describes the record headers of objects in the ROOT file. With the
GetListOfKeys() method you get the list of keys.
Get the list of keys from the demo.root file and print them.
Finding TKey objects
TFile::Get() method, you can find TKey objects.
Get() method finds the
TKey object with name h9.
Iterating over objects
TKeys of the
demo.root (see example → Creating a ROOT file) file are iterated.
The output is of the
iterate.C ROOT macro is:
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.
This example lists the objects on disk in the current directory.
To transfer an object from disk to memory, you have to use it explicitly.
hsimple.root reads it from the ROOT file and creates an object in memory.
The line beginning with
OBJ indicates that an
hprof, has been added in memory to this directory.
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
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
rootcling automatically creates one in the
ClassDef macro defined in
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.
Event class is defined in
$ROOTSYS/test/Event.h. It inherits from
A simple example of a class with several data members.
Event class is added to the dictionary with
EventDict.cxx file contains the automatically generated
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
Streamer calls TClass::ReadBuffer() when reading an
Event object. The
TClass::ReadBufferRead() method reads the information from buffer
R__b into the
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.
The pointer to objects
-> in the comment of the members
*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.
Variable length array
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.
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:
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.
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.
If the comment is absent or does not contain
nbits, the member is saved as a float.
max are present, they are saved with 32 bits precision.
max can be explicit values or expressions of values known to
rootlcing (for example
nbits is present, the member is saved as integer with nbits bits precision. For more details, see the I/O-tutorials
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.
Streamers with special additions
Streamer is generated by
rootcling. However, you can also create your own
Streamer. There are two reasons why you should create your own streamer:
- If you have a non-persistent data item that you want to initialize to a value depending on the data items you read.
- If you need to handle or schema evolution yourself.
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
- at the end of the class name indicates
rootcling not to generate a
In this example can see that the
Event class is the only one for which
rootcling is instructed not to generate a
+ sign indicates
rootcling to use the
The following is an example of a customized
Streamer takes a
TBuffer as a parameter, and first checks to see if this is a case of reading or writing the buffer.
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
with a call to the
- 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
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
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
fUniqueIDdata members. You gain space on the file, and you do not loose functionality if you do not use the
Streaming a TClonesArray
When writing a
, 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:
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
However, the drawback is when a
is written with
split=0 bypassing the
StreamerInfo of the class in the array being optimized, one cannot later use the
split > 0.
For example, there is a problem with the following scenario: a class
Foo has a
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
split > 1.
T2branch is created, the
StreamerInfo for the class
Bar is created with no optimization (mandatory for the split mode). The optimized
StreamerInfo is going to be used to read the
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
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.
ls() lists what is in the ROOT file.
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
object. When a XML file is open in write mode, you can use TObject::Write() to write an object into the XML file.