c++ - Come posso ottenere l'elenco dei file in una directory usando C o C ++?




12 Answers

Sfortunatamente lo standard C ++ non definisce un modo standard di lavorare con file e cartelle in questo modo.

Dal momento che non esiste una modalità cross platform, il modo migliore per utilizzare la piattaforma è utilizzare il modulo boost filesystem .

Metodo boost multipiattaforma:

La seguente funzione, dato un percorso di directory e un nome di file, ricerca ricorsivamente la directory e le sue sottodirectory per il nome del file, restituendo un valore bool e, in caso positivo, il percorso del file trovato.

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;
}

Fonte dalla pagina di boost menzionata sopra.

Per i sistemi basati su Unix / Linux:

Puoi usare opendir / readdir / closedir .

Il codice di esempio che cerca una directory per la voce `` nome '' è:

   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;

Codice sorgente dalle pagine man sopra.

Per i sistemi basati su Windows:

è possibile utilizzare le funzioni FindFirstFile / FindNextFile / FindClose dell'API Win32.

Il seguente esempio in C ++ mostra un utilizzo minimo di 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);
   }
}

Codice sorgente dalle pagine msdn precedenti.

c++ c file directory

Come posso determinare l'elenco dei file in una directory dal mio codice C o C ++?

Non ho il permesso di eseguire il comando ls e analizzare i risultati dal mio programma.




Una funzione è sufficiente, non è necessario utilizzare alcuna libreria di terze parti (per 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: come menzionato da @Sebastian, puoi cambiare *.* *.ext per ottenere solo i file EXT (cioè di un tipo specifico) in quella directory.




Raccomando di usare glob con questo wrapper riutilizzabile. Genera un vector<string> corrispondente ai percorsi dei file che si adattano al modello 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;
}

Che può quindi essere chiamato con un normale jolly di sistema come:

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



Perché non usare 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;
}






Manuale GNU FTW

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

Inoltre, a volte è bene andare direttamente alla fonte (gioco di parole). Puoi imparare molto guardando le viscere di alcuni dei comandi più comuni in Linux. Ho creato un semplice mirror dei coreutils di GNU su github (per la lettura).

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

Forse questo non affronta Windows, ma un certo numero di casi di utilizzo delle varianti Unix può essere ottenuto usando questi metodi.

Spero che sia d'aiuto...




Spero che questo codice ti aiuti.

#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;
}



Questo funziona per me. Mi dispiace se non riesco a ricordare la fonte. Probabilmente è da una pagina man.

#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/");
}



puoi ottenere tutti i file diretti nella tua directory radice usando std :: experimental :: filesystem :: directory_iterator (). Quindi, leggi il nome di questi file di percorso.

#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;
}



Questa risposta dovrebbe funzionare per gli utenti di Windows che hanno avuto problemi a ottenere questo funzionamento con Visual Studio con una qualsiasi delle altre risposte.

  1. Scarica il file dirent.h dalla pagina github. Ma è meglio usare semplicemente il file raw dirent.h e seguire i miei passi di seguito (è così che ho potuto farlo funzionare).

    Pagina Github per dirent.h per Windows: pagina Github per dirent.h

    Raw Dirent File: Raw dirent.h File

  2. Vai al tuo progetto e Aggiungi un nuovo elemento ( Ctrl + Shift + A ). Aggiungi un file di intestazione (.h) e chiamalo dirent.h.

  3. Incolla il codice file raw dirent.h nell'intestazione.

  4. Includi "dirent.h" nel tuo codice.

  5. Metti il ​​metodo void filefinder() sotto void filefinder() sotto il tuo codice e chiamalo dalla tua funzione main o modifica la funzione come vuoi usarlo.

    #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);
    }
    



Ho cercato di seguire l'esempio fornito in both answers e potrebbe valere la pena notare che sembra che std::filesystem::directory_entry sia stato modificato per non avere un overload dell'operatore << . Invece di std::cout << p << std::endl; Ho dovuto usare quanto segue per essere in grado di compilare e farlo funzionare:

#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;
}

provare a passare p da solo a std::cout << provocato un errore di sovraccarico mancante.




Questo ha funzionato per me. Scrive un file con solo i nomi (nessun percorso) di tutti i file. Quindi legge quel file txt e lo stampa per te.

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;
        }

    }



Related