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



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.

Question

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.




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("./*");



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 possa aiutare...




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



Sistema chiamalo!

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

Quindi leggi il file.

EDIT: questa risposta dovrebbe essere considerata un hack, ma funziona davvero (anche se in una piattaforma specifica) se non si ha accesso a soluzioni più eleganti.







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.




La risposta Shreevardhan funziona alla grande. Ma se si vuole usarlo in c ++ 14 basta fare una modifica namespace fs = experimental::filesystem;

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



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



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



Related