Как я могу получить список файлов в каталоге, используя C или C ++? - PullRequest
521 голосов
/ 04 марта 2009

Как определить список файлов в каталоге из моего кода C или C ++?

Мне не разрешено выполнять команду ls и анализировать результаты из моей программы.

Ответы [ 24 ]

8 голосов
/ 08 апреля 2011

Проверьте этот класс, который использует Win32 API. Просто создайте экземпляр, указав foldername, из которого вы хотите получить листинг, затем вызовите метод getNextFile, чтобы получить следующий filename из каталога. Я думаю, что нужно windows.h и 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;
    }

};
6 голосов
/ 12 ноября 2012

GNU Manual FTW

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

Кроме того, иногда хорошо идти прямо к источнику (каламбур). Вы можете многому научиться, взглянув на внутренности некоторых наиболее распространенных команд в Linux. Я установил простое зеркало GNU coreutils на github (для чтения).

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

Возможно, это не относится к Windows, но при использовании этих методов может быть несколько вариантов использования Unix.

Надеюсь, это поможет ...

4 голосов
/ 30 марта 2012
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;
}
3 голосов
/ 13 марта 2018

Shreevardhan ответ отлично работает. Но если вы хотите использовать его в C ++ 14, просто внесите изменения namespace fs = experimental::filesystem;

т.е.,

#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;
}
3 голосов
/ 19 февраля 2012

Надеюсь, этот код поможет вам.

#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;
}
2 голосов
/ 20 апреля 2018

вы можете получить все прямые файлы в вашем корневом каталоге, используя std :: эксперимент :: filesystem :: directory_iterator () Затем прочитайте имя этих файлов пути.

#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;
}
2 голосов
/ 22 мая 2017

Это работает для меня. Извините, если не могу вспомнить источник. Это, вероятно, со страницы руководства.

#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/");
}
2 голосов
/ 13 сентября 2014

Эта реализация реализует вашу цель, динамически заполняя массив строк содержимым указанного каталога.

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;
}
1 голос
/ 04 сентября 2018

Этот ответ должен работать для пользователей Windows, у которых возникли проблемы при работе с Visual Studio с любыми другими ответами.

  1. Загрузите файл dirent.h со страницы github. Но лучше просто использовать файл Raw dirent.h и следовать моим инструкциям ниже (именно так я его и заработал).

    Страница Github для dirent.h для Windows: Страница Github для dirent.h

    Файл Raw Dirent: Файл Raw dirent.h

  2. Перейдите в свой проект и добавьте новый элемент ( Ctrl + Shift + A ). Добавьте файл заголовка (.h) и назовите его dirent.h.

  3. Вставьте файл Raw dirent.h в ваш заголовок.

  4. Включите "dirent.h" в свой код.

  5. Вставьте приведенный ниже метод void filefinder() в свой код и вызовите его из функции main или отредактируйте функцию так, как вы хотите ее использовать.

    #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);
    }
    
1 голос
/ 10 апреля 2018

Поскольку файлы и подкаталоги каталога обычно хранятся в древовидной структуре, интуитивно понятным способом является использование алгоритма DFS для рекурсивного обхода каждого из них. Вот пример в операционной системе Windows с использованием основных файловых функций в io.h. Вы можете заменить эти функции на другой платформе. Что я хочу выразить, так это то, что основная идея DFS прекрасно соответствует этой проблеме.

#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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...