ROOT I/O

Reading and writing objects presents OO with probably its most severe challenge. As explained in Concepts: Objects & Classes objects are both code and data; it breaks the model to separate the two but that is just what happens when C++ objects are written to a file, only the data gets written. Clearly an OO model requires that objects are responsible for their own I/O and this seems to imply that one of the toughest problems gets left to the designer of the object to solve! In practice this is not the case, OO frameworks provides ways of generating code to do this. In the case of ROOT, TObject has a Streamer member function which is used to perform I/O. Any class that inherits from TObject, must supply its own version of the Streamer function. CINT, the interactive C++ interpreter can generate the Streamer function for any class, by processing its header file so long as a few simple rules are followed. Note that the Streamer function only has to deal with its own data members and in particular if these members are themselves objects then their Streamer functions are called to write them out. The same is true for the data members of the classes from which the class in question inherits. Consequently the Streamer function is very simple, with a single I/O statement for every data member and base class regardless how complex these are.

Although the Streamer function code is generated automatically, it is made available to the user who may want to change it for two reasons:-

The Streamer function is responsible for the process of converting an object's data into a stream of bytes and vice versa. It is passed a TBasket which holds the byte stream. The TBasket class overloads the << and >> operators so that it can perform this conversion with all the basic data types from which all objects' data are ultimately composed.

To output a object requires several more actions:-

This is done with another member function: Write, which is also inherited from TObject. The Write function is passed the name that will be used to retrieve the object later, for example:-
MyObject->Write("MyObject_1");
The first point to note is that no file name is supplied, whatever is the current directory in the current TFile will receive a copy of the object's data. So it is essential that a TFile object is created before attempting to output objects. A Tfile can have a set of directories (somewhat similar of HBOOK files), which are TDirectory objects. Each has a set of keys (TKey objects) that have the names of the objects written to the directory. The TKeys also have information about the position of the TBasket byte stream in the file. So sending an object its Write message results in the creation of a Tkey, and a TBasket, the invocation of the Streamer function to fill the TBasket, and the output of the TBasket. The TKey objects are written when the file is closed.

To do the inverse there is a Read member function that can be used to read on object back. For example:-

MyObject->Read("MyObject_1"); but this, of course, assumes that there is already an object and that it is O.K. to replace its data with the contents from the file. A rather more natural way is to send the Get message to the TFile object which will create the object and fill it with the data from file. For example, suppose f is the TFile object that holds the copy "MyObject_1", then to create the object, fill its data from the file and establish a pointer to it:-
MyClass *MyObject = (MyClass *) f.Get("MyObject_1"); 

Besides sending the Write message to a object, there are two other ways to output objects:-

In summary, the essential points are:- For more information see:-
Go Back to the The ROOT Crib Top Page


If you have any comments about this page please send them to Nick West