Open files in a directory with a for loop

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 :

{
	ifstream inn;
	char dir[]="C:/root/folder/";
	for (Int_t i=0; i<60; i++)
		{
			char name=i;
			inn.open(dir+name);
			Int_t num=0;
			string s1="no name",s2="no name";
			inn>>s1>>s2>>num;
			cout<<s1<<" "<<s2<<" "<<num<<endl;
		}
}

The files in the directory are named with integers from 1 to 60, and the first line contains some information about the data in the file. This approach doesn’t work because it prints out “no name no name 0” for 60 times…

I know it’s probably a silly problem,
but has someone any idea on how to fix it ? is there a ROOT function which does this instead ?

Thanks
Ian

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.

1 Like

Hi Bertrand!

It works perfectly now , thank you very much!

Cheers
Ian

Hello Bertrand,

after I run your macro I get list of files in the folder ( I make it unnamed macro) but after I am done with reading directory

the declaration
sprintf(iline,"%s/loudest_rms.txt",dirname);
ofstream Frms1(iline);

doesnt succeed. While if I declare it before I start reading directory it works. I am wondering why is that happening.

If you are using any ROOT version below 5.34, then you may face the following problem (for a solution see inside as well): [url]TSystemDirectory::GetListOfFile null pointer

Hey, im trying to do this script but it wont work. I copy and pasted the exact text from this post. It won’t work for me. I set the correct path and extensions but when I run the program through terminal/ROOT i get nothing. Just goes to the next command line in Terminal.

Anyone have any clue on what is wrong?

Go to the ROOT “tutorials” subdirectory and try (don’t forget to use ROOT 5.34 or newer):
root [0] .L list_files.cxx
root [1] list_files("./", “.root”); // you should see “gallery.root"
root [2] list_files(”./mlp/", “.root”); // you should see “mlpHiggs.root"
root [3] list_files(”./", “.C”); // you should see about 15 “.C” files
root [4] list_files("./mlp/", “.C”); // you should see “mlpHiggs.C” and “mlpRegression.C”

Note: in the end of the “list_files” function, one should add (just before returning): delete files;

BTW. If you are using any ROOT version below 5.34, replace the line: TList *files = dir.GetListOfFiles(); with: TString pwd(gSystem->pwd()); TList *files = dir.GetListOfFiles(); gSystem->cd(pwd.Data());

Hello,

I am new user of ROOT. I tried the following code by some changes but its not working. Please help me out.

void list_files(const char *dirname=“N:/”, const char *ext=".data") //I am trying to get all .data files from N: directory. But its not working.
{
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;
}
}
}
}

//While executing a program on ROOT command bar :
root[0] .L N:/list_files.c //files is located in N:/ directory
root[1] list_files(".abc",".data"); //.data file name staring with abc as a prefix

Please help me. How can I do this?

Thank you in advance.

Try: root[0] .L list_files.cxx root[1] list_files("N:/", ".data"); // list all "N:/*.data" files root[2] list_files("N:/", ".data", "abc"); // list all "N:/abc*.data" files using the following “list_files.cxx”: [code]#include “TSystem.h”
#include “TSystemFile.h”
#include “TSystemDirectory.h”
#include “TList.h”
#include “TString.h”

#include

void list_files(const char *dirname = “C:/root/folder/”,
const char *suffix = “.root”,
const char *prefix = “”)
{
if (!dirname || !(*dirname)) return; // just a precaution
TString pwd(gSystem->pwd());
TSystemDirectory dir(dirname, dirname);
TList *files = dir.GetListOfFiles();
gSystem->cd(pwd.Data()); // bug fix for ROOT prior to 5.34
if (files) {
TSystemFile file;
TString fname;
TIter next(files);
while ( (file = (TSystemFile
)next()) ) {
fname = file->GetName();
if ( !(file->IsDirectory()) &&
(!prefix || !(*prefix) || fname.BeginsWith(prefix)) &&
(!suffix || !(*suffix) || fname.EndsWith(suffix)) ) {
std::cout << fname.Data() << std::endl;
}
}
}
delete files;
}[/code]

Hello Sir,

Thanks a lot for a quick help. But its not working. I am pointing to a next root command. If you could help further that will be good.

Thank you.

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.