Question Comment puis-je obtenir la liste des fichiers dans un répertoire en utilisant C ou C ++?


Comment puis-je déterminer la liste des fichiers dans un répertoire à partir de mon code C ou C ++?

Je ne suis pas autorisé à exécuter le 'ls' commande et analyse les résultats de mon programme.


434
2018-03-04 19:35


origine


Réponses:


Dans les petites tâches simples, je n'utilise pas de boost, j'utilise dirent.h qui est également disponible pour Windows:

DIR *dir;
struct dirent *ent;
if ((dir = opendir ("c:\\src\\")) != NULL) {
  /* print all the files and directories within directory */
  while ((ent = readdir (dir)) != NULL) {
    printf ("%s\n", ent->d_name);
  }
  closedir (dir);
} else {
  /* could not open directory */
  perror ("");
  return EXIT_FAILURE;
}

C'est juste un petit fichier d'en-tête et fait la plupart des trucs simples dont vous avez besoin sans utiliser une grande approche basée sur un template comme boost (pas d'attaque, j'aime boost!).

L'auteur de la couche de compatibilité Windows est Toni Ronkko. Dans Unix, c'est un en-tête standard.

MISE À JOUR 2017:

En C ++ 17 il y a maintenant un moyen officiel de lister les fichiers de votre système de fichiers: std::filesystem. Il y a une excellente réponse de Shreevardhan ci-dessous avec ce code source:

#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    std::string path = "/path/to/directory";
    for (auto & p : fs::directory_iterator(path))
        std::cout << p << std::endl;
}

Envisager d'upvoting sa réponse, si vous utilisez l'approche C ++ 17.


603
2018-03-04 19:57



Malheureusement, le standard C ++ ne définit pas une manière standard de travailler avec des fichiers et des dossiers de cette manière.

Comme il n’existe pas de plate-forme croisée, la meilleure façon de multiplier les plates-formes consiste à utiliser une bibliothèque telle que booster le système de fichiers.

Méthode de renforcement de plate-forme croisée:

La fonction suivante, étant donné un chemin de répertoire et un nom de fichier, recherche récursivement le répertoire et ses sous-répertoires pour le nom de fichier, renvoyant un booléen, et en cas de succès, le chemin vers le fichier trouvé.

bool find_file(const path & dir_path,         // in this directory,
               const std::string & file_name, // search for this name,
               path & path_found)             // placing path here if found
{
    if (!exists(dir_path)) 
        return false;

    directory_iterator end_itr; // default construction yields past-the-end

    for (directory_iterator itr(dir_path); itr != end_itr; ++itr)
    {
        if (is_directory(itr->status()))
        {
            if (find_file(itr->path(), file_name, path_found)) 
                return true;
        }
        else if (itr->leaf() == file_name) // see below
        {
            path_found = itr->path();
            return true;
        }
    }
    return false;
}

Source de la page de boost mentionnée ci-dessus.


Pour les systèmes basés sur Unix / Linux: 

Vous pouvez utiliser opendir / readdir / fermé.

Exemple de code qui recherche dans un répertoire l'entrée `` name '':

   len = strlen(name);
   dirp = opendir(".");
   while ((dp = readdir(dirp)) != NULL)
           if (dp->d_namlen == len && !strcmp(dp->d_name, name)) {
                   (void)closedir(dirp);
                   return FOUND;
           }
   (void)closedir(dirp);
   return NOT_FOUND;

Code source des pages de manuel ci-dessus.


Pour un système basé sur Windows: 

vous pouvez utiliser l'API Win32 FindFirstFile / FindNextFile / FindClose les fonctions.

L'exemple C ++ suivant vous montre une utilisation minimale de FindFirstFile.

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

void _tmain(int argc, TCHAR *argv[])
{
   WIN32_FIND_DATA FindFileData;
   HANDLE hFind;

   if( argc != 2 )
   {
      _tprintf(TEXT("Usage: %s [target_file]\n"), argv[0]);
      return;
   }

   _tprintf (TEXT("Target file is %s\n"), argv[1]);
   hFind = FindFirstFile(argv[1], &FindFileData);
   if (hFind == INVALID_HANDLE_VALUE) 
   {
      printf ("FindFirstFile failed (%d)\n", GetLastError());
      return;
   } 
   else 
   {
      _tprintf (TEXT("The first file found is %s\n"), 
                FindFileData.cFileName);
      FindClose(hFind);
   }
}

Code source des pages msdn ci-dessus.


212
2018-03-04 19:38



C ++ 17 a maintenant un std::filesystem::directory_iterator, qui peut être utilisé comme

#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    std::string path = "/path/to/directory";
    for (const auto & p : fs::directory_iterator(path))
        std::cout << p << std::endl; // "p" is the directory entry. Get the path with "p.path()".
}

Aussi, std::filesystem::recursive_directory_iterator peut également parcourir les sous-répertoires.


170
2018-05-28 02:41



Une fonction suffit, vous n'avez pas besoin d'utiliser de bibliothèque tierce (pour Windows).

#include <Windows.h>

vector<string> get_all_files_names_within_folder(string folder)
{
    vector<string> names;
    string search_path = folder + "/*.*";
    WIN32_FIND_DATA fd; 
    HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd); 
    if(hFind != INVALID_HANDLE_VALUE) { 
        do { 
            // read all (real) files in current folder
            // , delete '!' read other 2 default folder . and ..
            if(! (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
                names.push_back(fd.cFileName);
            }
        }while(::FindNextFile(hFind, &fd)); 
        ::FindClose(hFind); 
    } 
    return names;
}

PS: comme mentionné par @Sebastian, vous pourriez changer *.* à *.ext afin d'obtenir uniquement les fichiers EXT (c'est-à-dire d'un type spécifique) dans ce répertoire.


73
2017-12-30 20:56



Pour une solution C uniquement, veuillez vérifier ceci. Il ne nécessite qu'un en-tête supplémentaire:

https://github.com/cxong/tinydir

tinydir_dir dir;
tinydir_open(&dir, "/path/to/dir");

while (dir.has_next)
{
    tinydir_file file;
    tinydir_readfile(&dir, &file);

    printf("%s", file.name);
    if (file.is_dir)
    {
        printf("/");
    }
    printf("\n");

    tinydir_next(&dir);
}

tinydir_close(&dir);

Quelques avantages par rapport aux autres options:

  • C'est portable - wraps POSIX dirent et Windows FindFirstFile
  • Il utilise readdir_r si disponible, ce qui signifie qu'il est (généralement) threadsafe
  • Supporte Windows UTF-16 via le même UNICODE macros
  • C'est C90 donc même les très anciens compilateurs peuvent l'utiliser

43
2018-02-04 01:06



Je recommande d'utiliser glob avec cette enveloppe réutilisable. Il génère un vector<string> correspondant aux chemins de fichier qui correspondent au motif glob:

#include <glob.h>
#include <vector>
using std::vector;

vector<string> globVector(const string& pattern){
    glob_t glob_result;
    glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
    vector<string> files;
    for(unsigned int i=0;i<glob_result.gl_pathc;++i){
        files.push_back(string(glob_result.gl_pathv[i]));
    }
    globfree(&glob_result);
    return files;
}

Qui peut ensuite être appelé avec un motif générique normal du système, tel que:

vector<string> files = globVector("./*");

26
2017-07-11 17:15



Voici un code très simple dans C++11 en utilisant boost::filesystem bibliothèque pour obtenir les noms de fichiers dans un répertoire (à l'exclusion des noms de dossiers):

#include <string>
#include <iostream>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;

int main()
{
    path p("D:/AnyFolder");
    for (auto i = directory_iterator(p); i != directory_iterator(); i++)
    {
        if (!is_directory(i->path())) //we eliminate directories
        {
            cout << i->path().filename().string() << endl;
        }
        else
            continue;
    }
}

La sortie est comme:

file1.txt
file2.dat

18
2018-06-25 16:51



Pourquoi ne pas utiliser glob()?

#include <glob.h>

glob_t glob_result;
glob("/your_directory/*",GLOB_TILDE,NULL,&glob_result);
for(unsigned int i=0; i<glob_result.gl_pathc; ++i){
  cout << glob_result.gl_pathv[i] << endl;
}

17
2018-02-10 18:57