I have a bunch of text files in a directory, and each text file is named "info1.txt", "info2.txt" and so on. How would I open up all of the text files in an array of ifstream objects without having to hard-code all my text file names in? I know the following code does not work, but I think it conveys the idea of what I want to do if it did work:
ifstream myFiles[5];
for(int i = 0; i < 5; i++){
myFiles[i].open("info" + i + ".txt");
}
I know the solution is probably very simple, but after a lot of research, trial and error I still haven't figured it out. Thanks!
The problem is, I guess, the part about dynamically creating the file name.
One of the simple solutions is to use std::ostringstream
to do it:
ifstream myFiles[5];
for(int i = 0; i < 5; i++){
ostringstream filename;
filename << "info" << i ".txt";
myFiles[i].open(filename.str());
}
If your library is to old for it to accept std::string
arguments in the call to open
then use
myFiles[i].open(filename.str().c_str());
For building the file names, I'd use std::ostringstream
and operator<<
.
If you want to use a container class like std::vector
(e.g. because you don't know at compile time how much big the array of ifstream
's will be), since std::ifstream
is not copyable, you can't use vector<ifstream>
, but you can use vector<shared_ptr<ifstream>>
or vector<unique_ptr<ifstream>>
; e.g.:
vector<shared_ptr<ifstream>> myFiles;
for (int i = 0; i < count; i++)
{
ostringstream filename;
filename << "info" << i << ".txt";
myFiles.push_back( make_shared<ifstream>( filename.str() ) );
}
With unique_ptr
(and C++11 move semantics):
vector<unique_ptr<ifstream>> myFiles;
for (int i = 0; i < count; i++)
{
ostringstream filename;
filename << "info" << i << ".txt";
unique_ptr<ifstream> file( new ifstream(filename.str()) );
myFiles.push_back( move(file) );
}
unqiue_ptr
is more efficient than shared_ptr
, since unique_ptr
is just a movable pointer, it's not reference counted (so there is less overhead than shared_ptr
). So, in C++11, you may want to prefer unique_ptr
if the ifstream
's are not shared outside the vector
container.
Your idea should work with a small change:
myFiles[i].open((std::string("info") + itoa(i) + ".txt").c_str());
// ^^^^^^^^^^^ ^^^^
Also note that, you cannot use std::vector
because ifstream
is not a copyable object. So continue using the array.
I usually use std::stringstream:
{
std::stringstream filename;
filename << "info" << i << ".txt" << std::ends;
myFiles[i].open(filename.str().c_str());
}
You can have an array of ifstream objects, but if you need a dynamic length, then you cannot do it this way, nor will std::vector<ifstream>
work.
So you will need pointers. std::vector<ifstream*>
will work but you might use shared_ptr so std::vector<shared_ptr<ifstream> >
will work. If you have unique_ptr
available you can use that instead of shared_ptr
.
Each element will then have to be created with new
.
You will also need to create the string properly, you can use a boost::format
or ostringstream
or even an old-fashioned sprintf
to do that.
By the way, I would search boost's filesystem library to see if they have a more dynamic ifstream
that can go happily in your vector without the messiness of shared_ptr.