1

I'm used to open just one file with the instruction:

ifstream file ("somefile.txt");      //that means that I know the name of my file

Now I have a big directory with a lot of files in it, and my program should open one by one all those files.

How can I do that?

Christophe
  • 68,716
  • 7
  • 72
  • 138

1 Answers1

7

The following methods will all populate a vector with the names of the files in a given directory.

Assume you've defined:

#include <vector>
#include <string>
typedef std::vector<std::string> stringvec;

opendir()/readdir()/closedir() (POSIX)

#include <sys/types.h>
#include <dirent.h>

void read_directory(const std::string& name, stringvec& v)
{
    DIR* dirp = opendir(name.c_str());
    struct dirent * dp;
    while ((dp = readdir(dirp)) != NULL) {
       v.push_back(dp->d_name);
    }
    closedir(dirp);
}

boost_filesystem

#include <boost/filesystem.hpp>

struct path_leaf_string
{
    std::string operator()(const boost::filesystem::directory_entry& entry) const
    {
        return entry.path().leaf().string();
    }
};

void read_directory(const std::string& name, stringvec& v)
{
    boost::filesystem::path p(name);
    boost::filesystem::directory_iterator start(p);
    boost::filesystem::directory_iterator end;
    std::transform(start, end, std::back_inserter(v), path_leaf_string());
}

std::filesystem (C++ 17)

#include <filesystem>

struct path_leaf_string
{
    std::string operator()(const std::filesystem::directory_entry& entry) const
    {
        return entry.path().leaf().string();
    }
};

void read_directory(const std::string& name, stringvec& v)
{
    std::filesystem::path p(name);
    std::filesystem::directory_iterator start(p);
    std::filesystem::directory_iterator end;
    std::transform(start, end, std::back_inserter(v), path_leaf_string());
}

FindFirstFile()/FindNextFile()/FindClose() (Windows)

#include <windows.h>

void read_directory(const std::string& name, stringvec& v)
{
    std::string pattern(name);
    pattern.append("\\*");
    WIN32_FIND_DATA data;
    HANDLE hFind;
    if ((hFind = FindFirstFile(pattern.c_str(), &data)) != INVALID_HANDLE_VALUE) {
        do {
            v.push_back(data.cFileName);
        } while (FindNextFile(hFind, &data) != 0);
        FindClose(hFind);
    }
}

Use one of these, and then you can iterate over the vector and open the files:

#include <iostream>
#include <fstream>

int main()
{
    const std::string directory = "/my/favourite/directory";
    stringvec v;
    read_directory(directory, v);
    for (auto filename : v) {
        std::string path = directory + "/" + filename;
        std::ifstream ifs(path);
        if (ifs) {
            // Read ifs here
        }
        else {
            std::cerr << "Couldn't open " << path << " for reading\n";
        }
    }
}
  • That's a great answer !! Just complement the boost one with the std c++17 one. – Christophe Nov 05 '17 at 18:11
  • Thank you very much for your answer. I'm a beginner C++ user so these codes sound very strange to me. I think the first one is the more simple to use. I have two questions. First: once i've created the vector (I guess it is v), how do I do my task? Do I just use something like ifstream file (v[i]) ? Second: I'm trying to run the code, but when I do the typedef it gives my an error "stringvec has not been declared". – Luigi Bernardi Nov 05 '17 at 18:27
  • @LuigiBernardi, I think the answer to your second question is to include `` and ``. I've added that to my answer. –  Nov 05 '17 at 18:30
  • Very kind of you, so fast to answer. Can you help me even with the first question? – Luigi Bernardi Nov 05 '17 at 18:43
  • I've added an example program, @LuigiBernardi. –  Nov 05 '17 at 18:50
  • I have even one last question, i promise. Where should the directory be? Same directory as the exe? Do I give the name of the directory here DIR* dirp = opendir(name.c_str()); ? (Replacing name with the real name?) – Luigi Bernardi Nov 05 '17 at 18:52
  • @LuigiBernardi, it doesn't matter where the directory is as long as you give its full path to `opendir()`. –  Nov 05 '17 at 18:54
  • Thank you! I think that with all your inf I can reach my task! Have a good day – Luigi Bernardi Nov 05 '17 at 18:59
  • You're welcome! Please accept my answer (click on the tick) if you're happy. –  Nov 05 '17 at 19:01
  • Sorry if i write to you again. I'm trying to compile the code, everything ok, but it gives me just this error: "filename does not name a type" referring to the line for (auto filename: v). – Luigi Bernardi Nov 05 '17 at 19:47
  • What compiler are you using? –  Nov 05 '17 at 19:48
  • I'm using dev c++ 5.11 – Luigi Bernardi Nov 05 '17 at 20:24
  • I think you need to do this: https://stackoverflow.com/questions/16951376/how-to-change-mode-from-c98-mode-in-dev-c-to-a-mode-that-supports-c0x-ran –  Nov 05 '17 at 20:25
  • yess!! it works! – Luigi Bernardi Nov 05 '17 at 20:32