Open files in a directory with a for loop

Hello sir,
Its working for a path C:/root but not working for N:/ means not working for other directive.
Thank you.

[quote=“zintinos”]Hi !
I’m new to ROOT and this Forum, so hopefully I’ve posted my problem in the right place! Right now I’m using Root in Windows 7, I’ve managed to plot histograms and fit them. Now i would like to loop inside a directory with the files containing the information for my histograms. I tried this way :
[/quote]

Actually, it’s not really right place, since this is not a ROOT-related problem, but your C++ problem:

{
	char dir[]="C:/root/folder/";
            ....
			inn.open(dir+name);
            ....
}

It’s not a big surprise, your code does not work the way you expected. When you do dir + name, do you really understand, what happens? You add some integer number to the pointer (after an array-to-pointer conversion) and got some pointer again as a result (quite soon it’s an invalid pointer, as soon as ‘name’ is bigger than number of elements in your array).
Try this to see what I mean:

void pointer_arithmetics()
{
    const char dir[] = "C:/root/folder/";
    for(unsigned i = 0; i < 5; ++i)
    {
        char name = i;//I have this line only because you have it.
        std::cout<<dir + name<<std::endl;
    }
}

So, either make you ‘dir’ to have TString type (and add name as Long_t or ULong_t, since TString has overloaded operator+ for these types) or use something else, but not pointer arithmetics .

[quote=“bellenot”]Hi Ian,

Here is a simple example showing how to list files in a directory:

void list_files(const char *dirname="C:/root/folder/", const char *ext=".root") { TSystemDirectory dir(dirname, dirname); TList *files = dir.GetListOfFiles(); if (files) { TSystemFile *file; TString fname; TIter next(files); while ((file=(TSystemFile*)next())) { fname = file->GetName(); if (!file->IsDirectory() && fname.EndsWith(ext)) { cout << fname.Data() << endl; } } } }
Hope this will help…

Cheers, Bertrand.[/quote]

Hello Bertrand,

I tried to implement your example but unfortunately it’s not working. This is the code:

[code]void list()
{
vector<char*> lista;

    TString path = gSystem->UnixPathName(gInterpreter->GetCurrentMacroName());
    path.ReplaceAll("ToBeDeleted.C", "");
    path.ReplaceAll("/./", "/");
    TSystemDirectory  dire(path+"2ndWeekNov-MPPCwLED/", path+"2ndWeekNov-MPPCwLED/");

    TList *files = dire.GetListOfFiles();
    TIter next(files);
    TSystemFile *file;
    TString fname;
    while((file = (TSystemFile*)next()))
    {
            fname = file->GetName();
            if(file->IsDirectory()) continue;

            lista.push_back(fname);
    }

    for(vector<char*>::iterator it = lista.begin(); it != lista.end(); it++) cout << *it << endl;

}
[/code]

and the error is the following:

[quote]/home/tristandnv/Documents/ROOT/v5-34-00-patches/macros/./ToBeDeleted.C: In function ‘void list()’:
/home/tristandnv/Documents/ROOT/v5-34-00-patches/macros/./ToBeDeleted.C:44:45: error: invalid conversion from ‘const char*’ to ‘std::vector<char*>::value_type {aka char*}’ [-fpermissive]
/usr/include/c++/4.6/bits/stl_vector.h:826:7: error: initializing argument 1 of ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = char*, _Alloc = std::allocator<char*>, std::vector<_Tp, _Alloc>::value_type = char*]’ [-fpermissive]
g++: error: /home/tristandnv/Documents/ROOT/v5-34-00-patches/macros/ToBeDeleted_C_ACLiC_dict.o: No such file or directory
Error in : Compilation failed!

[/quote]

Any suggestions?
Thanks in advance,
Daniel

Try to “implement” [url=https://root-forum.cern.ch/t/open-files-in-a-directory-with-a-for-loop/12471/9 example[/url]. :mrgreen:
Don’t miss [url=https://root-forum.cern.ch/t/how-to-define-and-assign-values-to-a-string-array-in-header/15250/8 and [url=https://root-forum.cern.ch/t/basic-histogram-using-previously-binned-data/15179/2 :wink:

Hi Daniel,

Try this:

void list()
{
   std::vector<std::string> lista;

   TString path = gSystem->UnixPathName(gInterpreter->GetCurrentMacroName());
   path.ReplaceAll("ToBeDeleted.C", "");
   path.ReplaceAll("/./", "/");
   TSystemDirectory  dire(path+"2ndWeekNov-MPPCwLED/", path+"2ndWeekNov-MPPCwLED/");

   TList *files = dire.GetListOfFiles();
   TIter next(files);
   TSystemFile *file;
   TString fname;
   while((file = (TSystemFile*)next())) {
      fname = file->GetName();
      if(file->IsDirectory()) continue;
      lista.push_back(fname.Data());
   }
   for(vector<string>::iterator it = lista.begin(); it != lista.end(); it++) cout << *it << endl;
}

Cheers, Bertrand.

Thanks W.E. Coyote and Bertrand for your help!

One question Bertrand: why didn’t my code work when using std::vector<char*> instead of std::vectorstd::string? Why was it giving this error:

error: invalid conversion from ‘const char*’ to ‘std::vector<char*>::value_type {aka char*}’ [-fpermissive]
/usr/include/c++/4.6/bits/stl_vector.h:826:7: error: initializing argument 1 of ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = char*, _Alloc = std::allocator<char*>, std::vector<_Tp, _Alloc>::value_type = char*]’ [-fpermissive]

?

Because a char* is a constant pointer and is not possible to assign a string to it and a string variable is a pointer to an array of characters that can be redefined? Now I’m using again c++ after a long time without using it and learning ROOT, so I’m not sure about some concepts. I had the impresion that what I was doing was valid. Please kindly clarify this conceptually.

Thanks in advance!
Daniel

C strings and C++ strings
Difference between string and char[] types in C++
std::string
TString
Character Sequences
Pointers
What is the difference between char a[] = “string”; and char *p = “string”;

OK, thanks!

Hello,
I want to create a different Tree for each file in the same .root file listed by above method. How could I do that?
My code is as below:


TFile *f = new TFile("staff.root","RECREATE");
TTree *tree ;
FILE *fp;

void list()
{
   std::vector<std::string> lista;

   TString path = gSystem->UnixPathName(gInterpreter->GetCurrentMacroName());
   path.ReplaceAll("ToBeDeleted.C", "");
   path.ReplaceAll("/./", "/");
   TSystemDirectory  dire(path+"2ndWeekNov-MPPCwLED/", path+"2ndWeekNov-MPPCwLED/");

   TList *files = dire.GetListOfFiles();
   TIter next(files);
   TSystemFile *file;
   TString fname;
   while((file = (TSystemFile*)next())) {
      fname = file->GetName();
      if(file->IsDirectory()) continue;
      lista.push_back(fname.Data());
   }
   for(vector<string>::iterator it = lista.begin(); it != lista.end(); it++) 
     cout << *it << endl;

    for(int i = 0;i<lista.size();i++)
    {
    char *filename;                      
    filename = lista.at(i).c_str());     [color=#FF0000]//What to do here? Becoz for fopen it should not be a Array.[/color]
        fp = fopen(filename, "r");  
    tree = new TTree("Tree1","PressureTime data");
     assignTreeData();
   }
 void assignTreeData()
 {  .....
      while (fgets(&line[0],127,fp)) {
      ..... sscanf(); 
    tree->Fill();
 }

tree->Write();
rootf->Write();
   
}

Its not working. Something is wrong. But I can not make out. If anybody can help?

You do not show any place where you open and close your “rootf”.
You have two choices, either you create one single “rootf” file and then you need to create your trees with distinct names, i.e. new TTree(“EachTreeDifferentName”, “same Title no problem”), or you keep the same name of every tree, but then you need to write them to distinct “rootf” files.

Sorry, I forgot to copy that part of code. Thanks for guidance. Ok. I have created trees with differnet names in the same .root file.

My code is as below:

TFile *f = new TFile("staff.root","RECREATE");
TTree *tree ;
FILE *fp;
char *token[20];

void list()
{
std::vector<std::string> lista;

TString path = gSystem->UnixPathName(gInterpreter->GetCurrentMacroName());
path.ReplaceAll("ToBeDeleted.C", "");
path.ReplaceAll("/./", "/");
TSystemDirectory dire(path+"2ndWeekNov-MPPCwLED/", path+"2ndWeekNov-MPPCwLED/");

TList *files = dire.GetListOfFiles();
TIter next(files);
TSystemFile *file;
TString fname;
while((file = (TSystemFile*)next())) {
fname = file->GetName();
if(file->IsDirectory()) continue;
lista.push_back(fname.Data());
}
for(vector<string>::iterator it = lista.begin(); it != lista.end(); it++)
cout << *it << endl;

for(int i = 0;i<lista.size();i++)
{
char *filename;
filename = lista.at(i).c_str()); //What to do here? Becoz for fopen it should not be a Array.
fp = fopen(filename, "r");
tokenOfFileName();
createTreeName();
assignTreeData();
}
void tokenOfFileName()
{         
         int count = 0;
	 token[0] = strtok(filename, "_.");
	   while (token[count] != NULL)
           {
		count++;
		token[count] = strtok (NULL, "_.");
	   }
		for (int i = 0; i <= count -1 ; i++)
		{
			printf ("%s \n", token[i]);
		}
}

void createTreeName()   
{
    treeName = strcat(token[0],token[3]);    
        cout << "TreeName : " << treeName << endl;
    tree = new TTree(treeName,"Tree");  
}

void assignTreeData()
{ .....
while (fgets(&line[0],127,fp)) {
..... sscanf();
tree->Fill();
}

tree->Write();
rootf->Write();
fclose(fp);   // Here I am trying to close the DataFile
}

Still have the same problem. Root is terminating automatically.

I think you are improperly using “strcat” in “createTreeName” (the “treeName” will be equal to the “token[0]”), unless you really know what you are doing there (see “man strcat” for details). One cannot check another places as it’s not clear what the “filename” in “tokenOfFileName” nor the “line[0]” in “createTreeName” are.
I believe you should stop using C strings (i.e. “chat *”, “char *[]”, …) and rewrite your code so that it solely uses C++ strings (i.e. std::string and/or TString).
Also, always try to pre-compile your source code using ACLiC (the compiler will find many possible source code bugs) … root [0] .L MySourceCode.cxx++

Hello,

Thanks for the guidance. I made changes to my program and its working. But I am facing another problem. I am creating one .root file and under .root file trying to create many trees. But its only creating 2 trees instead I wants to create many trees. One tree having 20480 records of data each.

Is more number of records in data file affecting to create many trees under one .root file ? Its not showing any error or warnings.

Thanks in advance.

Make sure that these trees have unique (unambiguous) “names” (their “titles” can be the same, though) and make sure that for every tree you call “MyTree->Write();”.

Thanks. Yes, I am assigning unique name to each tree and also doing MyTree->Write(). I am trying to read data from .data files to fill a tree. But it works for only two .data files.
Its not working for more than two data files. Means its creating only 2 trees for any .data file.

It’s difficult to say anything without the source code.
You can try one more thing. Add a line “MyRootFile->cd();” in two places:

  1. directly before you call “MyTree = new TTree(…);”
  2. directly before you call “MyTree->Write();”

I did some modifications to the original code but I am having a problem adding the histogram “hist”. I can see the correct histogram for each file but I was expecting to see the sum of all of them since I am using >>+. In fact the >> is not working at all because when the program finish, the histogram “hist” is empty.
How can I fix this? Thanks

void Plot(const Char_t *dirname= "out/", const Char_t *ext=".root") { TH1D *hist = new TH1D("hist","Reconstructed mass",500,0.45,0.55); Int_t count=0; TSystemDirectory dir(dirname, dirname); TList *files = dir.GetListOfFiles(); if (files) { TSystemFile *file; TString fname; TIter next(files); while ((file=(TSystemFile*)next())) { fname = file->GetName(); if (!file->IsDirectory() && fname.EndsWith(ext)) { //cout << fname.Data() << endl; Char_t eachfile[50]; sprintf(eachfile,"%s%s",dirname,fname.Data()); //cout << eachfile << endl; TFile f(eachfile); TTree *vertex = (TTree*)f.Get("vtx"); if (!vertex) {cout<< "No Vertex" << endl; continue;} vertex->Draw("Mass>>+hist",""); count++; if (count%10==0) cout << "Files: " << count << endl; gPad->Update(); } } } }

I’m afraid that the “logic” of the tree.Draw(“something>>[+]histo”) is a bit broken these days (well, I’ve been trying to “get it fixed”).

Try this “brutal fix”: // ... if (!vertex) {cout<< "No Vertex" << endl; continue;} hist->SetDirectory(gDirectory); // "attach" it to the current root file vertex->Draw("Mass>>+hist",""); hist->SetDirectory(gROOT); // "detach" it from the current root file count++; // ... or that one (note: instead of f.FindObject you can also try gPad->FindObject): // ... if (!vertex) {cout<< "No Vertex" << endl; continue;} vertex->Draw("Mass>>+hist",""); delete hist; // get rid of the old histogram hist = ((TH1D*)(f.FindObject("hist"))); // resume the new one hist->SetDirectory(gROOT); // "detach" it from the current root file count++; // ...

The second solution does not work, but the first one does the job. Thanks for the help

Hello, I have used this code from a long time without any problems, but recently I got something not working. All the files in the folder I read are label Hist_1.root, Hist_2.root, Hist_3.root … Before the files were being read in order (1,2,3,4,…), but now the are read in a random order. I tried in both linux and Mac, and Root 6 and 5 but it is not reading the files in order. Hope somebody knows what happen.