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

593

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 la lscommande et à analyser les résultats à partir de mon programme.

samoz
la source
7
Ceci est un doublon de 609236
chrish
1
@chrish - Oui mais celui-ci a le classique "Je n'ai pas le droit d'exécuter le 'l'"! C'est exactement ce que je ressentirais en 1ère année d'informatique. ; D <3 x
James Bedford
1
C et C ++ ne sont pas le même langage. Par conséquent, la procédure pour accomplir cette tâche sera différente dans les deux langues. Veuillez en choisir un et réétiqueter en conséquence.
MD XF
2
Et aucun de ces langages (autre que C ++ depuis C ++ 17) n'a même un concept de répertoire - donc toute réponse dépendra probablement de votre système d'exploitation, ou des bibliothèques d'abstraction que vous pourriez utiliser.
Toby Speight

Réponses:

810

Dans les petites et simples tâches, je n'utilise pas 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 choses simples dont vous avez besoin sans utiliser une grande approche basée sur des modèles comme boost (sans offense, j'aime boost!).

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

MISE À JOUR 2017 :

En C ++ 17 il y a maintenant un moyen officiel de la liste des 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 (const auto & entry : fs::directory_iterator(path))
        std::cout << entry.path() << std::endl;
}
Peter Parker
la source
5
@ArtOfWarfare: tinydir n'a même pas été créé lors de la réponse à cette question. C'est aussi un wrapper autour de dirent (POSIX) et FindFirstFile (Windows), tandis que dirent.h enveloppe simplement dirent pour Windows. Je pense que c'est un goût personnel, mais dirent.h se sent plus comme un standard
Peter Parker
7
@JoshC: parce que * ent est juste un pointeur renvoyé de la représentation interne. en fermant le répertoire, vous éliminerez également le * ent. Comme le * ent est uniquement pour la lecture, c'est une conception saine, je pense.
Peter Parker
42
les gens deviennent réels !! c'est une question de 2009 et elle n'a même pas mentionné VS. Donc, ne critiquez pas que votre IDE propriétaire (bien que très agréable) ne supporte pas les normes de système d'exploitation séculaires. Aussi ma réponse a dit qu'il est "disponible" pour Windows, pas "inclus" dans n'importe quel IDE à partir de maintenant et pour toujours ... Je suis sûr que vous pouvez télécharger dirent et le mettre dans certains include dir et le tour est joué.
Peter Parker
6
La réponse est trompeuse. Il doit commencer par: " ... J'utilise dirent.h , pour lequel une couche de compatibilité open-source Windows existe également ".
rustyx
10
Avec C ++ 14 il y en a std::experimental::filesystem, avec C ++ 17 il y en a std::filesystem. Voir la réponse de Shreevardhan ci-dessous. Donc pas besoin de bibliothèques tierces.
Roi Danton
347

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 & entry : fs::directory_iterator(path))
        std::cout << entry.path() << std::endl;
}

En outre, std::filesystem::recursive_directory_iteratorpeut itérer les sous - répertoires aussi bien.

Shreevardhan
la source
28
AFAIK peut également être utilisé en C ++ 14, mais il est encore au stade expérimental: namespace fs = std::experimental::filesystem;. Il semble que ça marche bien.
PeterK
7
Cela devrait être la réponse préférée pour une utilisation actuelle (à partir de C ++ 17)
diode verte
4
Faites attention lors du passage std::filesystem::pathà std::cout, les guillemets sont inclus dans la sortie. Pour éviter cela, ajoutez .string()au chemin pour effectuer une conversion explicite au lieu d'une conversion implicite (ici std::cout << p.string() << std::endl;). Exemple: coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3
Roi Danton
2
Qu'en est-il des caractères NON ASCII dans les noms de fichiers? Ne devrait pas std::wstringêtre utilisé ou quel est le type de l'itérateur?
anddero
2
Je ne sais pas si je suis seul dans ce domaine, mais sans lien avec -lstdc++fs, j'aurais un SIGSEGV (Address boundary error). Je n'ai trouvé nulle part dans la documentation que cela était nécessaire, et l'éditeur de liens n'a donné aucun indice non plus. Cela a fonctionné pour les deux g++ 8.3.0et clang 8.0.0-3. Quelqu'un at-il une idée de l'endroit où des choses comme celle-ci sont spécifiées dans les documents / spécifications?
swalog
229

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

Puisqu'il n'y a pas de moyen multiplateforme, le meilleur moyen multiplateforme est d'utiliser une bibliothèque telle que le module boost de système de fichiers .

Méthode de multiplication multiplateforme:

La fonction suivante, étant donné un chemin de répertoire et un nom de fichier, recherche récursivement dans le répertoire et ses sous-répertoires le nom de fichier, en renvoyant un booléen et, en cas de succès, le chemin d'accès au 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 à partir de la page boost mentionnée ci-dessus.

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

Vous pouvez utiliser opendir / readdir / closedir .

Un exemple de code qui recherche dans un répertoire l'entrée `` nom '' est:

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 les systèmes basés sur Windows:

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

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.

Brian R. Bondy
la source
Utilisation:FindFirstFile(TEXT("D:\\IMAGE\\MYDIRECTORY\\*"), &findFileData);
Константин Ван
7
Avec C ++ 14, il existe std::experimental::filesystem, avec C ++ 17 std::filesystem, qui ont des fonctionnalités similaires à boost (les bibliothèques sont dérivées de boost). Voir la réponse de Shreevardhan ci-dessous.
Roi Danton
Pour les fenêtres, reportez-vous à docs.microsoft.com/en-us/windows/desktop/FileIO/… pour plus de détails
FindOutIslamNow
90

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 pouvez passer *.*à *.extafin d'obtenir uniquement les fichiers EXT (c'est-à-dire d'un type spécifique) dans ce répertoire.

herohuyongtao
la source
20
Cette solution est spécifique à la plate-forme. C'est la raison pour laquelle vous avez besoin de bibliothèques tierces.
kraxor
9
@kraxor Oui, cela ne fonctionne que sous Windows, mais OP ne demande jamais d'avoir une solution multiplateforme. BTW, je préfère toujours choisir quelque chose sans utiliser de 3e bibliothèques (si possible).
herohuyongtao
7
@herohuyongtao OP n'a jamais spécifié de plateforme, et donner une solution fortement dépendante de la plateforme à une question générique peut être trompeur. (Et s'il y a une solution à une ligne qui ne fonctionne que sur PlayStation 3? Est-ce une bonne réponse ici?) Je vois que vous avez modifié votre réponse pour indiquer qu'elle ne fonctionne que sur Windows, je suppose que c'est bien comme ça.
kraxor
1
@herohuyongtao OP a mentionné qu'il ne peut pas analyser ls, ce qui signifie qu'il est probablement sous unix .. de toute façon, bonne réponse pour Windows.
Thomas
2
J'ai fini par utiliser un std::vector<std::wstring>et puis fileName.c_str()au lieu d'un vecteur de chaînes, qui ne compilerait pas.
PerryC
51

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:

  • Il est portable - encapsule dirent POSIX et Windows FindFirstFile
  • Il utilise readdir_rlorsqu'il est disponible, ce qui signifie qu'il est (généralement) threadsafe
  • Prend en charge Windows UTF-16 via les mêmes UNICODEmacros
  • C'est C90 donc même les très anciens compilateurs peuvent l'utiliser
congusbongus
la source
2
Très belle suggestion. Je ne l'ai pas encore testé sur un ordinateur Windows mais il fonctionne à
merveille
La bibliothèque ne prend pas en charge std :: string, vous ne pouvez donc pas passer file.c_str () à tinydir_open. Dans ce cas, il donne l'erreur C2664 lors de la compilation sur msvc 2015.
Stepan Yakovenko
33

Je recommande d'utiliser globavec cet emballage réutilisable. Il génère un vector<string>chemin de fichier correspondant au modèle de 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 modèle générique de système normal tel que:

vector<string> files = globVector("./*");
Chris Redford
la source
2
Testez que glob () renvoie zéro.
Camille Goudeseune
Je voudrais utiliser glob.h comme vous l'avez recommandé. Mais quand même, je ne peux pas inclure le fichier .h: ça dit No such file or directory. Pouvez-vous me dire comment résoudre ce problème s'il vous plaît?
Tofuw
Notez que cette routine ne va que d'un niveau (pas de récursivité). Il ne fait pas non plus de vérification rapide pour déterminer s'il s'agit d'un fichier ou d'un répertoire, ce que vous pouvez faire facilement en basculant GLOB_TILDEavec GLOB_TILDE | GLOB_MARKpuis en vérifiant les chemins se terminant par une barre oblique. Vous devrez y apporter une modification si vous en avez besoin.
Volomike
Cette plate-forme est-elle compatible?
Nikhil Augustine
Malheureusement, vous ne pouvez pas trouver de fichiers uniformément cachés via glob.
LmTinyToon
23

Voici un code très simple pour C++11utiliser la boost::filesystembibliothèque pour obtenir les noms de fichiers dans un répertoire (à l'exclusion des noms de dossier):

#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
Mauvais
la source
Salut, et où puis-je obtenir cette bibliothèque?
Alexander Leon VI
2
@Alexander De Leon: Vous pouvez obtenir cette bibliothèque sur leur site boost.org , lire d'abord le guide de démarrage, puis utiliser leur boost::filesystembibliothèque boost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htm
Bad
23

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;
}
Meekohi
la source
Cela pourrait être une meilleure réponse si vous expliquez les inclusions requises.
Volomike
2
Testez que glob () renvoie zéro!
orbitcowboy
C'est bien quand vous connaissez le fichier que vous recherchez tel que * .txt
Kemin Zhou
20

Je pense que l'extrait ci-dessous peut être utilisé pour répertorier tous les fichiers.

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

static void list_dir(const char *path)
{
    struct dirent *entry;
    DIR *dir = opendir(path);
    if (dir == NULL) {
        return;
    }

    while ((entry = readdir(dir)) != NULL) {
        printf("%s\n",entry->d_name);
    }

    closedir(dir);
}

Voici la structure de la structure dirent

struct dirent {
    ino_t d_ino; /* inode number */
    off_t d_off; /* offset to the next dirent */
    unsigned short d_reclen; /* length of this record */
    unsigned char d_type; /* type of file */
    char d_name[256]; /* filename */
};
Shrikant
la source
J'aimerais celui-ci.
selfboot
10

Essayez la méthode boost pour x-platform

http://www.boost.org/doc/libs/1_38_0/libs/filesystem/doc/index.htm

ou utilisez simplement votre fichier spécifique au système d'exploitation.

Tim
la source
Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien de référence. Les réponses de lien uniquement peuvent devenir invalides si la page liée change. - De l'avis
ice1000
@ ice1000 Sérieusement? Ce Q & A est de 2009
Tim
8

Découvrez cette classe qui utilise l'API Win32. Construisez simplement une instance en fournissant la liste à foldernamepartir de laquelle vous souhaitez la liste, puis appelez la getNextFileméthode pour obtenir la suivante à filenamepartir du répertoire. Je pense qu'il a besoin windows.het stdio.h.

class FileGetter{
    WIN32_FIND_DATAA found; 
    HANDLE hfind;
    char folderstar[255];       
    int chk;

public:
    FileGetter(char* folder){       
        sprintf(folderstar,"%s\\*.*",folder);
        hfind = FindFirstFileA(folderstar,&found);
        //skip .
        FindNextFileA(hfind,&found);        
    }

    int getNextFile(char* fname){
        //skips .. when called for the first time
        chk=FindNextFileA(hfind,&found);
        if (chk)
            strcpy(fname, found.cFileName);     
        return chk;
    }

};
robertvarga
la source
6

GNU Manual FTW

http://www.gnu.org/software/libc/manual/html_node/Simple-Directory-Lister.html#Simple-Directory-Lister

De plus, il est parfois bon d'aller directement à la source (jeu de mots voulu). Vous pouvez en apprendre beaucoup en examinant les entrailles de certaines des commandes les plus courantes de Linux. J'ai mis en place un simple miroir des coreutils de GNU sur github (pour la lecture).

https://github.com/homer6/gnu_coreutils/blob/master/src/ls.c

Peut-être que cela ne concerne pas Windows, mais un certain nombre de cas d'utilisation de variantes Unix peuvent être rencontrés en utilisant ces méthodes.

J'espère que cela pourra aider...

Homer6
la source
5

La réponse de Shreevardhan fonctionne très bien. Mais si vous voulez l'utiliser en c ++ 14, faites un changementnamespace fs = experimental::filesystem;

c'est à dire,

#include <string>
#include <iostream>
#include <filesystem>

using namespace std;
namespace fs = experimental::filesystem;

int main()
{
    string path = "C:\\splits\\";
    for (auto & p : fs::directory_iterator(path))
        cout << p << endl;
    int n;
    cin >> n;
}
Venkat Vinay
la source
4
char **getKeys(char *data_dir, char* tablename, int *num_keys)
{
    char** arr = malloc(MAX_RECORDS_PER_TABLE*sizeof(char*));
int i = 0;
for (;i < MAX_RECORDS_PER_TABLE; i++)
    arr[i] = malloc( (MAX_KEY_LEN+1) * sizeof(char) );  


char *buf = (char *)malloc( (MAX_KEY_LEN+1)*sizeof(char) );
snprintf(buf, MAX_KEY_LEN+1, "%s/%s", data_dir, tablename);

DIR* tableDir = opendir(buf);
struct dirent* getInfo;

readdir(tableDir); // ignore '.'
readdir(tableDir); // ignore '..'

i = 0;
while(1)
{


    getInfo = readdir(tableDir);
    if (getInfo == 0)
        break;
    strcpy(arr[i++], getInfo->d_name);
}
*(num_keys) = i;
return arr;
}
JasonYen2205
la source
3

J'espère que ce code vous aidera.

#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;

string wchar_t2string(const wchar_t *wchar)
{
    string str = "";
    int index = 0;
    while(wchar[index] != 0)
    {
        str += (char)wchar[index];
        ++index;
    }
    return str;
}

wchar_t *string2wchar_t(const string &str)
{
    wchar_t wchar[260];
    int index = 0;
    while(index < str.size())
    {
        wchar[index] = (wchar_t)str[index];
        ++index;
    }
    wchar[index] = 0;
    return wchar;
}

vector<string> listFilesInDirectory(string directoryName)
{
    WIN32_FIND_DATA FindFileData;
    wchar_t * FileName = string2wchar_t(directoryName);
    HANDLE hFind = FindFirstFile(FileName, &FindFileData);

    vector<string> listFileNames;
    listFileNames.push_back(wchar_t2string(FindFileData.cFileName));

    while (FindNextFile(hFind, &FindFileData))
        listFileNames.push_back(wchar_t2string(FindFileData.cFileName));

    return listFileNames;
}

void main()
{
    vector<string> listFiles;
    listFiles = listFilesInDirectory("C:\\*.txt");
    for each (string str in listFiles)
        cout << str << endl;
}
Oui
la source
4
-1. string2wchar_trenvoie l'adresse d'une variable locale. De plus, vous devriez probablement utiliser les méthodes de conversion disponibles dans WinAPI au lieu d'écrire les vôtres.
Daniel Kamil Kozar
3

Cette implémentation réalise votre objectif, remplissant dynamiquement un tableau de chaînes avec le contenu du répertoire spécifié.

int exploreDirectory(const char *dirpath, char ***list, int *numItems) {
    struct dirent **direntList;
    int i;
    errno = 0;

    if ((*numItems = scandir(dirpath, &direntList, NULL, alphasort)) == -1)
        return errno;

    if (!((*list) = malloc(sizeof(char *) * (*numItems)))) {
        fprintf(stderr, "Error in list allocation for file list: dirpath=%s.\n", dirpath);
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < *numItems; i++) {
        (*list)[i] = stringDuplication(direntList[i]->d_name);
    }

    for (i = 0; i < *numItems; i++) {
        free(direntList[i]);
    }

    free(direntList);

    return 0;
}
Giacomo Marciani
la source
Comment pourrais-je appeler cela? Je reçois des erreurs de segmentation lorsque j'essaie d'exécuter cette fonction sur le premier ifbloc. Je l'appelle avecchar **list; int numItems; exploreDirectory("/folder",list, numItems);
Hal T
2

Cela fonctionne pour moi. Je suis désolé si je ne me souviens pas de la source. Il s'agit probablement d'une page de manuel.

#include <ftw.h>

int AnalizeDirectoryElement (const char *fpath, 
                            const struct stat *sb,
                            int tflag, 
                            struct FTW *ftwbuf) {

  if (tflag == FTW_F) {
    std::string strFileName(fpath);

    DoSomethingWith(strFileName);
  }
  return 0; 
}

void WalkDirectoryTree (const char * pchFileName) {

  int nFlags = 0;

  if (nftw(pchFileName, AnalizeDirectoryElement, 20, nFlags) == -1) {
    perror("nftw");
  }
}

int main() {
  WalkDirectoryTree("some_dir/");
}
ENHering
la source
2

vous pouvez obtenir tous les fichiers directement dans votre répertoire racine en utilisant std :: experimental :: filesystem :: directory_iterator (). Ensuite, lisez le nom de ces fichiers de chemins.

#include <iostream>
#include <filesystem>
#include <string>
#include <direct.h>
using namespace std;
namespace fs = std::experimental::filesystem;
void ShowListFile(string path)
{
for(auto &p: fs::directory_iterator(path))  /*get directory */
     cout<<p.path().filename()<<endl;   // get file name
}

int main() {

ShowListFile("C:/Users/dell/Pictures/Camera Roll/");
getchar();
return 0;
}
ducPham
la source
2

Cette réponse devrait fonctionner pour les utilisateurs de Windows qui ont eu du mal à le faire fonctionner avec Visual Studio avec l'une des autres réponses.

  1. Téléchargez le fichier dirent.h depuis la page github. Mais il vaut mieux simplement utiliser le fichier Raw dirent.h et suivre mes étapes ci-dessous (c'est ainsi que je l'ai fait fonctionner).

    Page Github pour dirent.h pour Windows: Page Github pour dirent.h

    Fichier Dirent brut: fichier dirent.h brut

  2. Accédez à votre projet et ajoutez un nouvel élément ( Ctrl+ Shift+ A). Ajoutez un fichier d'en-tête (.h) et nommez-le dirent.h.

  3. Collez le code Raw dirent.h File dans votre en-tête.

  4. Incluez "dirent.h" dans votre code.

  5. Mettez la void filefinder()méthode ci-dessous dans votre code et appelez-la depuis votre mainfonction ou modifiez la fonction comme vous voulez l'utiliser.

    #include <stdio.h>
    #include <string.h>
    #include "dirent.h"
    
    string path = "C:/folder"; //Put a valid path here for folder
    
    void filefinder()
    {
        DIR *directory = opendir(path.c_str());
        struct dirent *direntStruct;
    
        if (directory != NULL) {
            while (direntStruct = readdir(directory)) {
                printf("File Name: %s\n", direntStruct->d_name); //If you are using <stdio.h>
                //std::cout << direntStruct->d_name << std::endl; //If you are using <iostream>
            }
        }
        closedir(directory);
    }
ZKR
la source
1

Appelez-le!

system( "dir /b /s /a-d * > file_names.txt" );

Ensuite, lisez simplement le fichier.

EDIT: Cette réponse doit être considérée comme un hack, mais elle fonctionne vraiment (bien que d'une manière spécifique à la plate-forme) si vous n'avez pas accès à des solutions plus élégantes.

Catalyseur
la source
7
Je ne suis pas autorisé à exécuter la commande «ls» et à analyser les résultats à partir de mon programme. Je savais qu'il y aurait quelqu'un qui enverrait quelque chose comme ça ...
yyny
1

Étant donné que les fichiers et les sous-répertoires d'un répertoire sont généralement stockés dans une arborescence, une méthode intuitive consiste à utiliser l'algorithme DFS pour parcourir récursivement chacun d'eux. Voici un exemple dans le système d'exploitation Windows en utilisant les fonctions de base des fichiers dans io.h. Vous pouvez remplacer ces fonctions dans une autre plate-forme. Ce que je veux exprimer, c'est que l'idée de base de DFS répond parfaitement à ce problème.

#include<io.h>
#include<iostream.h>
#include<string>
using namespace std;

void TraverseFilesUsingDFS(const string& folder_path){
   _finddata_t file_info;
   string any_file_pattern = folder_path + "\\*";
   intptr_t handle = _findfirst(any_file_pattern.c_str(),&file_info);
   //If folder_path exsist, using any_file_pattern will find at least two files "." and "..", 
   //of which "." means current dir and ".." means parent dir
   if (handle == -1){
       cerr << "folder path not exist: " << folder_path << endl;
       exit(-1);
   }
   //iteratively check each file or sub_directory in current folder
   do{
       string file_name=file_info.name; //from char array to string
       //check whtether it is a sub direcotry or a file
       if (file_info.attrib & _A_SUBDIR){
            if (file_name != "." && file_name != ".."){
               string sub_folder_path = folder_path + "\\" + file_name;                
               TraverseFilesUsingDFS(sub_folder_path);
               cout << "a sub_folder path: " << sub_folder_path << endl;
            }
       }
       else
            cout << "file name: " << file_name << endl;
    } while (_findnext(handle, &file_info) == 0);
    //
    _findclose(handle);
}
tkingcer
la source
1

J'ai essayé de suivre l'exemple donné dans les deux réponses et il pourrait être intéressant de noter qu'il semble std::filesystem::directory_entryavoir été modifié pour ne pas avoir de surcharge de l' <<opérateur. Au lieu de cela, std::cout << p << std::endl;j'ai dû utiliser ce qui suit pour pouvoir compiler et le faire fonctionner:

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

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

essayer de passer ppar lui-même pour std::cout <<entraîner une erreur de surcharge manquante.

StarKiller4011
la source
1

S'appuyant sur ce que herohuyongtao a publié et quelques autres messages:

http://www.cplusplus.com/forum/general/39766/

Quel est le type d'entrée attendu de FindFirstFile?

Comment convertir wstring en chaîne?

Ceci est une solution Windows.

Puisque je voulais passer dans std :: string et retourner un vecteur de chaînes, j'ai dû faire quelques conversions.

#include <string>
#include <Windows.h>
#include <vector>
#include <locale>
#include <codecvt>

std::vector<std::string> listFilesInDir(std::string path)
{
    std::vector<std::string> names;
    //Convert string to wstring
    std::wstring search_path = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(path);
    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)) 
            {
                //convert from wide char to narrow char array
                char ch[260];
                char DefChar = ' ';
                WideCharToMultiByte(CP_ACP, 0, fd.cFileName, -1, ch, 260, &DefChar, NULL);
                names.push_back(ch);
            }
        } 
        while (::FindNextFile(hFind, &fd));
        ::FindClose(hFind);
    }
    return names;
}
tzg
la source
Si vous savez que vous n'utiliserez que plusieurs octets, vous pourriez utiliser WIN32_FIND_DATAA, FindFirstFileAet FindNextFileA. Ensuite, il ne sera pas nécessaire de convertir le résultat en plusieurs octets ou l'entrée en unicode.
Kiran Thilak
0

Juste quelque chose que je veux partager et merci pour le matériel de lecture. Jouez avec la fonction un peu pour la comprendre. Vous l'aimerez peut-être. e signifie extension, p est pour chemin et s est pour séparateur de chemin.

Si le chemin est passé sans terminer le séparateur, un séparateur sera ajouté au chemin. Pour l'extension, si une chaîne vide est entrée, la fonction renverra tout fichier qui n'a pas d'extension dans son nom. Si une seule étoile a été entrée, tous les fichiers du répertoire seront retournés. Si la longueur e est supérieure à 0 mais n'est pas un simple *, un point sera ajouté à e si e n'avait pas contenu de point à la position zéro.

Pour une valeur de retour. Si une carte de longueur nulle est renvoyée, rien n'a été trouvé mais le répertoire était bien ouvert. Si l'index 999 est disponible à partir de la valeur de retour mais que la taille de la carte n'est que de 1, cela signifie qu'il y a eu un problème avec l'ouverture du chemin du répertoire.

Notez que pour plus d'efficacité, cette fonction peut être divisée en 3 fonctions plus petites. En plus de cela, vous pouvez créer une fonction d'appelant qui détectera la fonction qu'il va appeler en fonction de l'entrée. Pourquoi est-ce plus efficace? Dit que si vous allez récupérer tout ce qui est un fichier, en utilisant cette méthode, la sous-fonction qui a été conçue pour récupérer tous les fichiers ne fera que récupérer tous les fichiers et n'a pas besoin d'évaluer toute autre condition inutile à chaque fois qu'il trouve un fichier.

Cela s'appliquerait également lorsque vous récupérez des fichiers sans extension. Une fonction spécifique construite à cet effet n'évaluerait la météo que si l'objet trouvé est un fichier et si le nom du fichier contient ou non un point.

L'économie peut ne pas être importante si vous ne lisez que les répertoires contenant moins de fichiers. Mais si vous lisez une grande quantité de répertoire ou si le répertoire contient quelques centaines de milliers de fichiers, cela pourrait être une énorme économie.

#include <stdio.h>
#include <sys/stat.h>
#include <iostream>
#include <dirent.h>
#include <map>

std::map<int, std::string> getFile(std::string p, std::string e = "", unsigned char s = '/'){
    if ( p.size() > 0 ){
        if (p.back() != s) p += s;
    }
    if ( e.size() > 0 ){
        if ( e.at(0) != '.' && !(e.size() == 1 && e.at(0) == '*') ) e = "." + e;
    }

    DIR *dir;
    struct dirent *ent;
    struct stat sb;
    std::map<int, std::string> r = {{999, "FAILED"}};
    std::string temp;
    int f = 0;
    bool fd;

    if ( (dir = opendir(p.c_str())) != NULL ){
        r.erase (999);
        while ((ent = readdir (dir)) != NULL){
            temp = ent->d_name;
            fd = temp.find(".") != std::string::npos? true : false;
            temp = p + temp;

            if (stat(temp.c_str(), &sb) == 0 && S_ISREG(sb.st_mode)){
                if ( e.size() == 1 && e.at(0) == '*' ){
                    r[f] = temp;
                    f++;
                } else {
                    if (e.size() == 0){
                        if ( fd == false ){
                            r[f] = temp;
                            f++;
                        }
                        continue;
                    }

                    if (e.size() > temp.size()) continue;

                    if ( temp.substr(temp.size() - e.size()) == e ){
                        r[f] = temp;
                        f++;
                    }
                }
            }
        }

        closedir(dir);
        return r;
    } else {
        return r;
    }
}

void printMap(auto &m){
    for (const auto &p : m) {
        std::cout << "m[" << p.first << "] = " << p.second << std::endl;
    }
}

int main(){
    std::map<int, std::string> k = getFile("./", "");
    printMap(k);
    return 0;
}
Kevin Ng
la source
0
#include<iostream>
#include <dirent.h>
using namespace std;
char ROOT[]={'.'};

void listfiles(char* path){
    DIR * dirp = opendir(path);
    dirent * dp;
    while ( (dp = readdir(dirp)) !=NULL ) {
         cout << dp->d_name << " size " << dp->d_reclen<<std::endl;
    }
    (void)closedir(dirp);
}

int main(int argc, char **argv)
{
    char* path;
    if (argc>1) path=argv[1]; else path=ROOT;

    cout<<"list files in ["<<path<<"]"<<std::endl;
    listfiles(path);

    return 0;
}
Stan Sokolov
la source
-1

Cela a fonctionné pour moi. Il écrit un fichier avec juste les noms (pas de chemin) de tous les fichiers. Ensuite, il lit ce fichier txt et l'imprime pour vous.

void DisplayFolderContent()
    {

        system("dir /n /b * > file_names.txt");
        char ch;
        std::fstream myStream("file_names.txt", std::fstream::in);
        while (myStream.get(ch))
        {
            std::cout << ch;
        }

    }
Cesar Alejandro Montero Orozco
la source