TFile and WINDOWS (ROOT 5.26.00)

Hi Rooters,

I’ve got troubles with TFile on WINDOWS (Xp)

     TString rootfile ="/home/...../file.root";
     TFile tf(rootfile.Data(), "RECREATE");
     _datatree->Write();
     tf.Close();

where _datatree is roughly a TNtupleD,
is a piece of code which does its job on UNIX. the Root file rootfile is built (and i can use it after) , the tuple is filled. When i get the StartViewer (or check values with Scan() ) from _datatree, i have no troubles.

On Win32, my rootfile looks like this
TString rootfile = “C:/TEST/file.root”; (if i set it explicitly)
The piece of code above does’nt work :
_datatree is not filled and even though the root file is produced, it is not usable.
if i skip TFile use

    _datatree->Write();

I can easily use Scan(), StartViewer(), Draw() but of course, ihave not my Root file (that i’d want to use for example with a _datatree->AddFriend(“Tree Name”, “rootfile Name”)
I used several things like

  • Set the root file as TString rootfile = “C:\TEST\file.root”
  • Set the root file as TString rootfile = “file.root” (but it seems that the full file name is then “C:\TEST/file.root”)
    and other things like use methods from gSystem ExpandPathName() and UnixFileName(), but same troubles!
    How can i build a good Root file with such a path for rootfile?

Hi,

Well, it works for me (at least with the trunk):

C:\Users\bellenot>root -l root [0] TString rootfile = "C:/Users/bellenot/root/tutorials/test.root"; root [1] TFile tf(rootfile.Data(), "RECREATE"); root [2] TH1F h("h","h",1000,-3,3); root [3] h.FillRandom("gaus",50000); root [4] h.Write(); root [5] tf.Close(); root [6] .q C:\Users\bellenot>root -l root [0] TString rootfile = "C:/Users/bellenot/root/tutorials/test.root"; root [1] TFile tf(rootfile.Data()); root [2] .ls TFile** C:/Users/bellenot/root/tutorials/test.root TFile* C:/Users/bellenot/root/tutorials/test.root KEY: TH1F h;1 h root [3] h->Draw() <TCanvas::MakeDefCanvas>: created default TCanvas with name c1 root [4]
[color=#FF0000]Note: The target directory must exist![/color]

And you can also try to use the Windows way of writing pathes:

C:\Users\bellenot>root -l root [0] TString rootfile = "C:\\Users\\bellenot\\root\\tutorials\\test.root"; root [1] TFile tf(rootfile.Data()); root [2] .ls TFile** C:\Users\bellenot\root\tutorials\test.root TFile* C:\Users\bellenot\root\tutorials\test.root KEY: TH1F h;1 h root [3]

Cheers, Bertrand.

Hi Bertrand,

I tested the following code

root [0] TString rootfile = "C:/root/share/macros/test.root";
root [1] TFile tf(rootfile.Data(), "RECREATE");
root [2] TH1F h("h","h",1000,-3,3);
root [3] h.FillRandom("gaus",50000);
root [4] h.Write();
root [5] tf.Close();
root [6] .q

Then ROOT has crashed. Though the rootfile is usable.

Same thing with

TString rootfile = "C:\\root\\share\\macros\\test.root";

Hi,

Just create the histogram on the heap instead of on the stack (use operator new) as shown below:

root [0] TString rootfile = "C:/Users/bellenot/root/test/test.root";
root [1] TFile tf(rootfile.Data(), "RECREATE");
root [2] TH1F *h = new TH1F("h","h",1000,-3,3);
root [3] h->FillRandom("gaus",50000);
root [4] h->Write();
root [5] tf.Close();
root [6] .q

And I would also advise to use this syntax for opening the file:

Since this will work with any kind of file (e.g accessing it via the web via “http://…”)

Cheers, Bertrand.

Hi Bertrand, sorry for the delay!

I have tested all your advices: in fact i needed to use this syntax for TFile! Thanks!

But it seems that troubles didn’t mainly come from TFiles
The better is I explain the context:
Still with WIN32

I have a code with a class KLASS with a method:

Bool_t KLASS::writeTuple()
      {

   TupleD = new TNtupleD("superTuple","superTuple","E"); //(TupleD is effectivly a TNtupleD *)
   Double_t *inValues = new Double_t[1];
   inValues[0]=16.0;
   TupleD->Fill(inValues);
   TupleD->Scan("*");                  GOOD RETURN!

   // Clean
   inValues = 0;
   delete[] inValues;
         
   // Save the tuple in a TFile
   TString rootfile = TString("C:\\root\\share\\macros\\test.root");
   TFile *tf = TFile::Open(rootfile.Data(), "RECREATE");
   TupleD->Write();
   tf->Close();
   return  kTRUE;
 }

Then I use this macro

{
  KLASS * class = new KLASS();
  class->writeTuple();

  class->startViewer();//OK same as TupleD->StartViewer()
  class->draw("E");//OK  
  class->getTuple()->Draw("E");//OK Both are same as TupleD->Draw("E")

  //class->Scan("*");//NOOK
  //class->scan("*");//NOOK
  //class->getTuple()->Scan("*");//NOOK Same as TupleD->Scan("*")
}

I don’t know if it lacks something when i fill TupleD, but it seems i’ve troubles with Scan() method.

On the other part, i have the macro:

{
  TString rootfile = TString("C:\\root\\share\\macros\\test.root");
  TFile *tf= TFile::Open(rootfile.Data());
  //superTuple->Scan("*");
  //superTuple->Draw("E");
  superTuple->StartViewer();
  //tf->Close(); Ok, I need to comment this line if i want to access the graph through the viewer
}

which works fine (so i think my tfile problem is effectively resolved!)

Cédric

Hi Cedric,

No idea what could go wrong… Could you provide a [color=#BF0000]running[/color] piece of code reproducing the problem, please?

Cheers, Bertrand.

Hi Bertrand,

Here is a little main with the criminal class (ok, there is more include files than i actually need !)
(compiled with VC ++ 9.0)

#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <map>
#include <windows.h>
#include "Windows4Root.h"

using std::cout;
using std::endl;
using std::map;
using std::ios;
using std::string;
#include "TROOT.h"
#include "TSystem.h"
#include "TFile.h"
#include "TNtupleD.h"
#include "TH1.h"
#include "TCanvas.h"

class KLASS : public TNamed {
  private:
    TNtupleD*     TupleD; 
  public:
 
    KLASS(){};
    ~KLASS(){};
    TNtupleD *getTuple()
    {
       return TupleD;
    }

    Bool_t writeTuple()
    {
      TupleD = new TNtupleD("superTuple","superTuple","E"); 
      Double_t *inValues = new Double_t[1];
      inValues[0]=16.0;
      TupleD->Fill(inValues);
      TupleD->Scan("*");// GOOD RETURN!

      // Clean
      inValues = 0;
      delete[] inValues;
         
      // Save the tuple in a TFile
      TString rootfile = TString("C:\\root\\share\\macros\\test.root");
      TFile *tf = TFile::Open(rootfile.Data(), "RECREATE");
      TupleD->Write();
      tf->Close();
      return  kTRUE;
    }
};

int main(int argc, char *argv[]) {
  KLASS * classe = new KLASS();
  classe->writeTuple();

  classe->getTuple()->Scan("*");//NOOK Same as TupleD->Scan("*")
  return 0;
}

So the first macro I wrote in the previous post is now in the main block.

Hi Cedric,

OK, the problem comes from the fact that you close the file and then use the TupleD, which is gone when the file is closed, as it is owned by the TFile (see the “Object Ownership” chapter of the User’s Guide).
Adding TupleD->SetDirectory(0); as shown below will solve the problem:

      // Save the tuple in a TFile
      TString rootfile = TString("C:\\root\\share\\macros\\test.root");
      TFile *tf = TFile::Open(rootfile.Data(), "RECREATE");
      TupleD->SetDirectory(0); // <---- avoid the TNtupleD to be owned by the file
      TupleD->Write();
      tf->Close();
      return  kTRUE;

Cheers, Bertrand.

  • OK, with the setDirectory() method i can scan my tuple! Thanks!
  • On the other part when after i want to launch a StartViewer() it seems it needs to be linked to a TDirectory because it is empty!
    I saw in the the User’s Guide (“Object Ownership”) that i can use again setDirectory() but here i used in the code before using StartViewer() on TupleD:
    TFile *ttf = TFile::Open(rootfile.Data(), “UPDATE”);
    TupleD->setDirectory(0) <–still mandatory
    TupleD->StartViewer();
    ttf->Close();<-- same trouble as before, iget the startviewer (filled) if i don’t keep this line, but after this is a crash!

to be continued…
EDIT:

To make it clearer:

With last modifications in KLASS, in a macro

  • I can use Scan() method with classe->getTuple()->Scan();(and Draw() method)
  • I can use classe->getTuple()->Startviewer() but… the viewer is empty (what i understood as the fact i need to link a directory to TupleD through TFile::Open or setDirectory() )

These means the user of KLASS needs to define a TFile in his macro (OK, what does any user of ROOT but I need to use KLASS!)

To prevent the user of KLASS from doing this, we can define a new method in KLASS called startviewer() which is the few lines I wrote above:

void startviewer ()
{
TString rootfile = “C:\root\share\macros\test.root”;
TFile *ttf = TFile::Open(rootfile.Data(), “UPDATE”);
TupleD->setDirectory(0) <–still mandatory
TupleD->StartViewer();
ttf->Close();
}

Even if can find the right way to make this method functional, the user could decide to use classe->getTuple()->StartViewer() instead of startviewer() …
I wonder if i have to choose between close my TFile or keep functionnalities (ok, it’s not really a choice I need both things!)

I precise that SetDirectory(“The current TDirectory”) followed by TupleD->StartViewer() works! (but in macros, classe->getTuple()->StartViewer() is still lost)

Hi Cedric,

Note that one of the point of using a TTree is to be able to use/analyze data set that do not fit in memory. The TTree structure is set to work efficiently by retrieving the data from the file and thus we strongly recommend to not detach the TTree for its TFile (and of course this requires to not close nor delete the TFile until you no longer need the TTree object).

For completeness, note that when detaching a TTree from its TFile, you ought to do: tree->LoadBaskets(); // Load from the file any data not yet in memory tree->SetDirectory(...);Cheers,
Philippe.

Hi Philippe,

I take your advice into consideration!
Thanks a lot!