Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RFile.hxx
Go to the documentation of this file.
1/// \file ROOT/RFile.hxx
2/// \ingroup Base ROOT7
3/// \author Giacomo Parolini <giacomo.parolini@cern.ch>
4/// \date 2025-03-19
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8#ifndef ROOT7_RFile
9#define ROOT7_RFile
10
11#include <ROOT/RError.hxx>
12
13#include <deque>
14#include <functional>
15#include <iostream>
16#include <memory>
17#include <string_view>
18#include <typeinfo>
19#include <variant>
20
21class TFile;
22class TIterator;
23class TKey;
24
25namespace ROOT {
26namespace Experimental {
27
28class RKeyInfo;
29class RFile;
30
31namespace Internal {
32
34
35/// Returns an **owning** pointer to the object referenced by `key`. The caller must delete this pointer.
36/// This method is meant to only be used by the pythonization.
37[[nodiscard]] void *RFile_GetObjectFromKey(RFile &file, const RKeyInfo &key);
38
40
41} // namespace Internal
42
43namespace Detail {
44
45/// Given a "path-like" string (like foo/bar/baz), returns a pair `{ dirName, baseName }`.
46/// `baseName` will be empty if the string ends with '/'.
47/// `dirName` will be empty if the string contains no '/'.
48/// `dirName`, if not empty, always ends with a '/'.
49/// NOTE: this function does no semantic checking or path expansion, nor does it interact with the
50/// filesystem in any way (so it won't follow symlink or anything like that).
51/// Moreover it doesn't trim the path in any way, so any leading or trailing whitespaces will be preserved.
52/// This function does not perform any copy: the returned string_views have the same lifetime as `path`.
53std::pair<std::string_view, std::string_view> DecomposePath(std::string_view path);
54
55}
56
57class RFileKeyIterable;
58
59/**
60\class ROOT::Experimental::RKeyInfo
61\ingroup RFile
62\brief Information about an RFile object's Key.
63
64Every object inside a ROOT file has an associated "Key" which contains metadata on the object, such as its name, type
65etc.
66Querying this information can be done via RFile::ListKeys(). Reading an object's Key
67doesn't deserialize the full object, so it's a relatively lightweight operation.
68*/
72
73public:
74 enum class ECategory : std::uint16_t {
76 kObject,
78 };
79
80private:
81 std::string fPath;
82 std::string fTitle;
83 std::string fClassName;
84 std::uint16_t fCycle = 0;
86
87public:
88 /// Returns the absolute path of this key, i.e. the directory part plus the object name.
89 const std::string &GetPath() const { return fPath; }
90 /// Returns the base name of this key, i.e. the name of the object without the directory part.
91 std::string GetBaseName() const { return std::string(Detail::DecomposePath(fPath).second); }
92 const std::string &GetTitle() const { return fTitle; }
93 const std::string &GetClassName() const { return fClassName; }
94 std::uint16_t GetCycle() const { return fCycle; }
95 ECategory GetCategory() const { return fCategory; }
96};
97
98/// The iterable returned by RFile::ListKeys()
100 using Pattern_t = std::string;
101
102 TFile *fFile = nullptr;
104 std::uint32_t fFlags = 0;
105
106public:
107 class RIterator {
108 friend class RFileKeyIterable;
109
111 // This is ugly, but TList returns an (owning) pointer to a polymorphic TIterator...and we need this class
112 // to be copy-constructible.
113 std::shared_ptr<TIterator> fIter;
114 std::string fDirPath;
115
116 // Outlined to avoid including TIterator.h
117 RIterStackElem(TIterator *it, const std::string &path = "");
118 // Outlined to avoid including TIterator.h
120
121 // fDirPath doesn't need to be compared because it's implied by fIter.
122 bool operator==(const RIterStackElem &other) const { return fIter == other.fIter; }
123 };
124
125 // Using a deque to have pointer stability
126 std::deque<RIterStackElem> fIterStack;
128 const TKey *fCurKey = nullptr;
129 std::uint16_t fRootDirNesting = 0;
130 std::uint32_t fFlags = 0;
131
132 void Advance();
133
134 // NOTE: `iter` here is an owning pointer (or null)
135 RIterator(TIterator *iter, Pattern_t pattern, std::uint32_t flags);
136
137 public:
139 using iterator_category = std::input_iterator_tag;
140 using difference_type = std::ptrdiff_t;
142 using pointer = const value_type *;
143 using reference = const value_type &;
144
146 {
147 Advance();
148 return *this;
149 }
150 value_type operator*();
151 bool operator!=(const iterator &rh) const { return !(*this == rh); }
152 bool operator==(const iterator &rh) const { return fIterStack == rh.fIterStack; }
153 };
154
155 RFileKeyIterable(TFile *file, std::string_view rootDir, std::uint32_t flags)
156 : fFile(file), fPattern(std::string(rootDir)), fFlags(flags)
157 {
158 }
159
160 RIterator begin() const;
161 RIterator end() const;
162};
163
164/**
165\class ROOT::Experimental::RFile
166\ingroup RFile
167\brief An interface to read from, or write to, a ROOT file, as well as performing other common operations.
168
169## When and why should you use RFile
170
171RFile is a modern and minimalistic interface to ROOT files, both local and remote, that can be used instead of TFile
172when you only need basic Put/Get operations and don't need the more advanced TFile/TDirectory functionalities.
173It provides:
174- a simple interface that makes it easy to do things right and hard to do things wrong;
175- more robustness and better error reporting for those operations;
176- clearer ownership semantics expressed through the type system.
177
178RFile doesn't cover the entirety of use cases covered by TFile/TDirectory/TDirectoryFile and is not
179a 1:1 replacement for them. It is meant to simplify the most common use cases by following newer standard C++
180practices.
181
182## Ownership model
183
184RFile handles ownership via smart pointers, typically std::unique_ptr.
185
186When getting an object from the file (via RFile::Get) you get back a unique copy of the object. Calling `Get` on the
187same object twice produces two independent clones of the object. The ownership over that object is solely on the caller
188and not shared with the RFile. Therefore, the object will remain valid after closing or destroying the RFile that
189generated it. This also means that any modification done to the object are **not** reflected to the file automatically:
190to update the object in the file you need to write it again (via RFile::Overwrite).
191
192RFile::Put and RFile::Overwrite are the way to write objects to the file. Both methods take a const reference to the
193object to write and don't change the ownership of the object in any way. Calling Put or Overwrite doesn't guarantee that
194the object is immediately written to the underlying storage: to ensure that, you need to call RFile::Flush (or close the
195file).
196
197## Directories
198
199Even though there is no equivalent of TDirectory in the RFile API, directories are still an existing concept in RFile
200(since they are a concept in the ROOT binary format). However they are for now only interacted with indirectly, via the
201use of filesystem-like string-based paths. If you Put an object in an RFile under the path "path/to/object", "object"
202will be stored under directory "to" which is in turn stored under directory "path". This hierarchy is encoded in the
203ROOT file itself and it can provide some optimization and/or conveniences when querying objects.
204
205For the most part, it is convenient to think about RFile in terms of a key-value storage where string-based paths are
206used to refer to arbitrary objects. However, given the hierarchical nature of ROOT files, certain filesystem-like
207properties are applied to paths, for ease of use: the '/' character is treated specially as the directory separator;
208multiple '/' in a row are collapsed into one (since RFile doesn't allow directories with empty names).
209
210At the moment, RFile doesn't allow getting directories via Get, nor writing ones via Put (this may change in the
211future).
212
213## Sample usage
214Opening an RFile (for writing) and writing an object to it:
215~~~{.cpp}
216auto rfile = ROOT::RFile::Recreate("my_file.root");
217auto myObj = TH1D("h", "h", 10, 0, 1);
218rfile->Put(myObj.GetName(), myObj);
219~~~
220
221Opening an RFile (for reading) and reading an object from it:
222~~~{.cpp}
223auto rfile = ROOT::RFile::Open("my_file.root");
224auto myObj = file->Get<TH1D>("h");
225~~~
226*/
228 friend void *Internal::RFile_GetObjectFromKey(RFile &file, const RKeyInfo &key);
230
231 /// Flags used in PutInternal()
232 enum PutFlags {
233 /// When encountering an object at the specified path, overwrite it with the new one instead of erroring out.
235 /// When overwriting an object, preserve the existing one and create a new cycle, rather than removing it.
237 };
238
239 std::unique_ptr<TFile> fFile;
240
241 // Outlined to avoid including TFile.h
242 explicit RFile(std::unique_ptr<TFile> file);
243
244 /// Gets object `path` from the file and returns an **owning** pointer to it.
245 /// The caller should immediately wrap it into a unique_ptr of the type described by `type`.
246 [[nodiscard]] void *GetUntyped(std::string_view path,
247 std::variant<const char *, std::reference_wrapper<const std::type_info>> type) const;
248
249 /// Writes `obj` to file, without taking its ownership.
250 void PutUntyped(std::string_view path, const std::type_info &type, const void *obj, std::uint32_t flags);
251
252 /// \see Put
253 template <typename T>
254 void PutInternal(std::string_view path, const T &obj, std::uint32_t flags)
255 {
256 PutUntyped(path, typeid(T), &obj, flags);
257 }
258
259 /// Given `path`, returns the TKey corresponding to the object at that path (assuming the path is fully split, i.e.
260 /// "a/b/c" always means "object 'c' inside directory 'b' inside directory 'a'").
261 /// IMPORTANT: `path` must have been validated/normalized via ValidateAndNormalizePath() (see RFile.cxx).
262 TKey *GetTKey(std::string_view path) const;
263
264public:
266 kListObjects = 1 << 0,
267 kListDirs = 1 << 1,
269 };
270
271 // This is arbitrary, but it's useful to avoid pathological cases
272 static constexpr int kMaxPathNesting = 1000;
273
274 ///// Factory methods /////
275
276 /// Opens the file for reading. `path` may be a regular file path or a remote URL.
277 /// \throw ROOT::RException if the file at `path` could not be opened.
278 static std::unique_ptr<RFile> Open(std::string_view path);
279
280 /// Opens the file for reading/writing, overwriting it if it already exists.
281 /// \throw ROOT::RException if a file could not be created at `path` (e.g. if the specified
282 /// directory tree does not exist).
283 static std::unique_ptr<RFile> Recreate(std::string_view path);
284
285 /// Opens the file for updating, creating a new one if it doesn't exist.
286 /// \throw ROOT::RException if the file at `path` could neither be read nor created
287 /// (e.g. if the specified directory tree does not exist).
288 static std::unique_ptr<RFile> Update(std::string_view path);
289
290 ///// Instance methods /////
291
292 // Outlined to avoid including TFile.h
294
295 /// Retrieves an object from the file.
296 /// `path` should be a string such that `IsValidPath(path) == true`, otherwise an exception will be thrown.
297 /// See \ref ValidateAndNormalizePath() for info about valid path names.
298 /// If the object is not there returns a null pointer.
299 template <typename T>
300 std::unique_ptr<T> Get(std::string_view path) const
301 {
302 void *obj = GetUntyped(path, typeid(T));
303 return std::unique_ptr<T>(static_cast<T *>(obj));
304 }
305
306 /// Puts an object into the file.
307 /// The application retains ownership of the object.
308 /// `path` should be a string such that `IsValidPath(path) == true`, otherwise an exception will be thrown.
309 /// See \ref ValidateAndNormalizePath() for info about valid path names.
310 ///
311 /// Throws a RException if `path` already identifies a valid object or directory.
312 /// Throws a RException if the file was opened in read-only mode.
313 template <typename T>
314 void Put(std::string_view path, const T &obj)
315 {
316 PutInternal(path, obj, /* flags = */ 0);
317 }
318
319 /// Puts an object into the file, overwriting any previously-existing object at that path.
320 /// The application retains ownership of the object.
321 ///
322 /// If an object already exists at that path, it is kept as a backup cycle unless `backupPrevious` is false.
323 /// Note that even if `backupPrevious` is false, any existing cycle except the latest will be preserved.
324 ///
325 /// Throws a RException if `path` is already the path of a directory.
326 /// Throws a RException if the file was opened in read-only mode.
327 template <typename T>
328 void Overwrite(std::string_view path, const T &obj, bool backupPrevious = true)
329 {
330 std::uint32_t flags = kPutAllowOverwrite;
332 PutInternal(path, obj, flags);
333 }
334
335 /// Writes all objects and the file structure to disk.
336 /// Returns the number of bytes written.
337 size_t Flush();
338
339 /// Flushes the RFile if needed and closes it, disallowing any further reading or writing.
340 void Close();
341
342 /// Returns an iterable over all keys of objects and/or directories written into this RFile starting at path
343 /// `basePath` (defaulting to include the content of all subdirectories).
344 /// By default, keys referring to directories are not returned: only those referring to leaf objects are.
345 /// If `basePath` is the path of a leaf object, only `basePath` itself will be returned.
346 /// `flags` is a bitmask specifying the listing mode.
347 /// If `(flags & kListObjects) != 0`, the listing will include keys of non-directory objects (default);
348 /// If `(flags & kListDirs) != 0`, the listing will include keys of directory objects;
349 /// If `(flags & kListRecursive) != 0`, the listing will recurse on all subdirectories of `basePath` (default),
350 /// otherwise it will only list immediate children of `basePath`.
351 ///
352 /// Example usage:
353 /// ~~~{.cpp}
354 /// for (RKeyInfo key : file->ListKeys()) {
355 /// /* iterate over all objects in the RFile */
356 /// cout << key.GetPath() << ";" << key.GetCycle() << " of type " << key.GetClassName() << "\n";
357 /// }
358 /// for (RKeyInfo key : file->ListKeys("", kListDirs|kListObjects|kListRecursive)) {
359 /// /* iterate over all objects and directories in the RFile */
360 /// }
361 /// for (RKeyInfo key : file->ListKeys("a/b", kListObjects)) {
362 /// /* iterate over all objects that are immediate children of directory "a/b" */
363 /// }
364 /// for (RKeyInfo key : file->ListKeys("foo", kListDirs|kListRecursive)) {
365 /// /* iterate over all directories under directory "foo", recursively */
366 /// }
367 /// ~~~
368 RFileKeyIterable ListKeys(std::string_view basePath = "", std::uint32_t flags = kListObjects | kListRecursive) const
369 {
370 return RFileKeyIterable(fFile.get(), basePath, flags);
371 }
372
373 /// Retrieves information about the key of object at `path`, if one exists.
374 std::optional<RKeyInfo> GetKeyInfo(std::string_view path) const;
375
376 /// Prints the internal structure of this RFile to the given stream.
377 void Print(std::ostream &out = std::cout) const;
378};
379
380} // namespace Experimental
381} // namespace ROOT
382
383#endif
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
bool operator==(const iterator &rh) const
Definition RFile.hxx:152
bool operator!=(const iterator &rh) const
Definition RFile.hxx:151
std::deque< RIterStackElem > fIterStack
Definition RFile.hxx:126
RIterator(TIterator *iter, Pattern_t pattern, std::uint32_t flags)
Definition RFile.cxx:397
The iterable returned by RFile::ListKeys()
Definition RFile.hxx:99
RFileKeyIterable(TFile *file, std::string_view rootDir, std::uint32_t flags)
Definition RFile.hxx:155
An interface to read from, or write to, a ROOT file, as well as performing other common operations.
Definition RFile.hxx:227
void Close()
Flushes the RFile if needed and closes it, disallowing any further reading or writing.
Definition RFile.cxx:528
static constexpr int kMaxPathNesting
Definition RFile.hxx:272
static std::unique_ptr< RFile > Recreate(std::string_view path)
Opens the file for reading/writing, overwriting it if it already exists.
Definition RFile.cxx:224
std::unique_ptr< TFile > fFile
Definition RFile.hxx:239
size_t Flush()
Writes all objects and the file structure to disk.
Definition RFile.cxx:523
static std::unique_ptr< RFile > Update(std::string_view path)
Opens the file for updating, creating a new one if it doesn't exist.
Definition RFile.cxx:214
void Print(std::ostream &out=std::cout) const
Prints the internal structure of this RFile to the given stream.
Definition RFile.cxx:509
void PutInternal(std::string_view path, const T &obj, std::uint32_t flags)
Definition RFile.hxx:254
TKey * GetTKey(std::string_view path) const
Given path, returns the TKey corresponding to the object at that path (assuming the path is fully spl...
Definition RFile.cxx:238
std::optional< RKeyInfo > GetKeyInfo(std::string_view path) const
Retrieves information about the key of object at path, if one exists.
Definition RFile.cxx:534
static std::unique_ptr< RFile > Open(std::string_view path)
Opens the file for reading.
Definition RFile.cxx:204
std::unique_ptr< T > Get(std::string_view path) const
Retrieves an object from the file.
Definition RFile.hxx:300
void * GetUntyped(std::string_view path, std::variant< const char *, std::reference_wrapper< const std::type_info > > type) const
Gets object path from the file and returns an owning pointer to it.
Definition RFile.cxx:283
void Overwrite(std::string_view path, const T &obj, bool backupPrevious=true)
Puts an object into the file, overwriting any previously-existing object at that path.
Definition RFile.hxx:328
void PutUntyped(std::string_view path, const std::type_info &type, const void *obj, std::uint32_t flags)
Writes obj to file, without taking its ownership.
Definition RFile.cxx:319
PutFlags
Flags used in PutInternal()
Definition RFile.hxx:232
@ kPutOverwriteKeepCycle
When overwriting an object, preserve the existing one and create a new cycle, rather than removing it...
Definition RFile.hxx:236
@ kPutAllowOverwrite
When encountering an object at the specified path, overwrite it with the new one instead of erroring ...
Definition RFile.hxx:234
RFileKeyIterable ListKeys(std::string_view basePath="", std::uint32_t flags=kListObjects|kListRecursive) const
Returns an iterable over all keys of objects and/or directories written into this RFile starting at p...
Definition RFile.hxx:368
void Put(std::string_view path, const T &obj)
Puts an object into the file.
Definition RFile.hxx:314
RFile(std::unique_ptr< TFile > file)
Definition RFile.cxx:234
Information about an RFile object's Key.
Definition RFile.hxx:69
const std::string & GetClassName() const
Definition RFile.hxx:93
const std::string & GetTitle() const
Definition RFile.hxx:92
ECategory GetCategory() const
Definition RFile.hxx:95
std::string GetBaseName() const
Returns the base name of this key, i.e. the name of the object without the directory part.
Definition RFile.hxx:91
std::uint16_t GetCycle() const
Definition RFile.hxx:94
const std::string & GetPath() const
Returns the absolute path of this key, i.e. the directory part plus the object name.
Definition RFile.hxx:89
A log configuration for a channel, e.g.
Definition RLogger.hxx:98
A ROOT file is an on-disk file, usually with extension .root, that stores objects in a file-system-li...
Definition TFile.h:130
Iterator abstract base class.
Definition TIterator.h:30
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
std::pair< std::string_view, std::string_view > DecomposePath(std::string_view path)
Given a "path-like" string (like foo/bar/baz), returns a pair { dirName, baseName }.
Definition RFile.cxx:193
ROOT::RLogChannel & RFileLog()
Definition RFile.cxx:24
void * RFile_GetObjectFromKey(RFile &file, const RKeyInfo &key)
Returns an owning pointer to the object referenced by key.
Definition RFile.cxx:549
TFile * GetRFileTFile(RFile &rfile)
Definition RFile.cxx:555
bool operator==(const RIterStackElem &other) const
Definition RFile.hxx:122
RIterStackElem(TIterator *it, const std::string &path="")
Definition RFile.cxx:390