C 또는 C ++를 사용하여 디렉토리에서 파일 목록을 얻으려면 어떻게해야합니까?


593

C 또는 C ++ 코드 내부에서 디렉토리의 파일 목록을 어떻게 확인할 수 있습니까?

ls명령 을 실행하고 프로그램 내에서 결과를 구문 분석 할 수 없습니다 .


7
이것은 609236
— chrish


1
@ chrish-네,하지만 이건 고전적인 "나는 'ls'을 (를) 실행할 수 없습니다." 그건 바로 내가 컴퓨터 과학의 1 년을 느낄 것 방법에 대해 설명합니다. ; D <3 x
— James Bedford

1
C와 C ++는 같은 언어가 아닙니다. 따라서이 작업을 수행하는 절차는 두 언어가 다릅니다. 하나를 선택하고 그에 따라 태그를 다시 지정하십시오.
— MD XF

2
그리고 C ++ 17 이후 C ++ 이외의 언어도 디렉토리 개념이 없으므로 OS 또는 사용중인 추상화 라이브러리에 대한 대답이 달라질 수 있습니다.
— Toby Speight

답변:


809

작고 간단한 작업에서 boost를 사용하지 않고 Windows에서도 사용할 수있는 dirent.h 를 사용합니다.

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

그것은 단지 작은 헤더 파일이며 boost와 같은 큰 템플릿 기반 접근 방식을 사용하지 않고도 필요한 대부분의 간단한 작업을 수행합니다.

Windows 호환성 계층의 작성자는 Toni Ronkko입니다. 유닉스에서는 표준 헤더입니다.

2017 업데이트 :

C ++ 17에는 이제 파일 시스템의 파일을 나열하는 공식적인 방법이 있습니다 std::filesystem. 이 소스 코드와 함께 Shreevardhan 의 훌륭한 답변 이 아래에 있습니다.

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

5
@ArtOfWarfare :이 질문에 대한 답변이있을 때 tinydir도 만들지 않았습니다. 또한 dirent (POSIX) 및 FindFirstFile (Windows) 주위의 래퍼 인 반면 dirent.h는 Windows 용 dirent를 래핑합니다. 개인적 취향이라고 생각하지만 dirent.h는 더 표준으로 느낍니다.
— Peter Parker

7
@JoshC : * ent는 내부 표현의 반환 포인터 일 뿐이므로 디렉토리를 닫으면 * ent도 제거됩니다. * ent는 읽기 전용이므로 이것은 제정신 디자인입니다.
— 피터 파커

42
사람들은 진짜를 얻는다!! 이것은 2009 년의 질문이며 VS에 대해서는 언급하지 않았습니다. 따라서 여러분의 모든 독점 (아주 훌륭하지만) IDE가 수세기의 오래된 OS 표준을 지원하지 않는다고 비난하지 마십시오. 또한 내 대답은 그것이 지금까지 모든 IDE에서 "포함"되지 않은 Windows 용 "사용 가능"이라고 말했다.
— 피터 파커

6
답은 오해의 소지가 있습니다. " ... Windows 오픈 소스 호환성 계층 도 존재 하는 dirent.h를 사용합니다 ."로 시작해야합니다 .
— rustyx

10
C ++ 14에는 std::experimental::filesystem, C ++ 17에는 std::filesystem. 아래 Shreevardhan의 답변을 참조하십시오. 따라서 타사 라이브러리가 필요하지 않습니다.
— Roi Danton

347

C ++ 17에는 이제을 std::filesystem::directory_iterator사용할 수 있습니다.

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

또한 std::filesystem::recursive_directory_iterator서브 디렉토리도 반복 할 수 있습니다.


28
AFAIK는 C ++ 14에서도 사용할 수 있지만 여전히 실험적 namespace fs = std::experimental::filesystem;입니다. 그래도 작동하는 것 같습니다.
— PeterK

7
이것은 현재 사용을 위해 선호되는 답변이어야합니다 (C ++ 17로 시작)
— green diod

4
통과 할 때에주의가 std::filesystem::path에 std::cout인용 부호는 출력에 포함된다. 이를 피하려면 .string()경로에 추가 하여 암시 적 변환 (여기 std::cout << p.string() << std::endl;) 대신 명시 적으로 수행하십시오 . 예 : coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3
— Roi Danton

2
파일 이름의 비 ASCII 문자는 어떻습니까? 사용해서는 안 std::wstring되거나 반복기의 유형은 무엇입니까?
— anddero

2
나는 이것에 혼자 있는지 확실하지 않지만에 링크하지 않으면을 -lstdc++fs얻을 수 있습니다 SIGSEGV (Address boundary error). 문서에서 이것이 필요하다는 것을 찾을 수 없었으며 링커는 아무런 단서도주지 않았습니다. 이것은 모두 일을 g++ 8.3.0하고 clang 8.0.0-3. 누구든지 문서 / 사양에서 이와 같은 것들이 지정된 위치에 대한 통찰력이 있습니까?
— swalog

229

불행히도 C ++ 표준은 이러한 방식으로 파일 및 폴더를 사용하는 표준 방법을 정의하지 않습니다.

크로스 플랫폼 방식이 없으므로 최상의 크로스 플랫폼 방식은 boost 파일 시스템 모듈 과 같은 라이브러리를 사용하는 것 입니다.

크로스 플랫폼 부스트 방법 :

디렉토리 경로 및 파일 이름이 지정된 다음 함수는 디렉토리 및 해당 서브 디렉토리에서 파일 이름을 재귀 적으로 검색하여 부울을 리턴하고 성공하면 발견 된 파일의 경로를 리턴합니다.

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

위에서 언급 한 부스트 페이지의 소스.

유닉스 / 리눅스 기반 시스템의 경우 :

opendir / readdir / closedir을 사용할 수 있습니다 .

디렉토리에서``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;

위의 매뉴얼 페이지의 소스 코드.

Windows 기반 시스템의 경우 :

Win32 API FindFirstFile / FindNextFile / FindClose 함수를 사용할 수 있습니다 .

다음 C ++ 예제는 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);
   }
}

위의 msdn 페이지의 소스 코드


사용법 :FindFirstFile(TEXT("D:\\IMAGE\\MYDIRECTORY\\*"), &findFileData);
— Константин Ван

7
C ++ 14에는 std::experimental::filesystem, C ++ 17에는 std::filesystemboost와 비슷한 기능이 있습니다 (lib는 boost에서 파생 됨). 아래 Shreevardhan의 답변을 참조하십시오.
— Roi Danton

자세한 내용은 docs.microsoft.com/en-us/windows/desktop/FileIO/… 를 참조하십시오.
— FindOutIslamNow

90

하나의 기능만으로도 타사 라이브러리 (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;
}

추신 : @Sebastian에서 언급 한 바와 같이, 당신은 변경 될 수 있습니다 *.*에 *.ext해당 디렉토리에만 EXT-파일을 얻기 위해 (즉, 특정 유형의)에서.


20
이 솔루션은 플랫폼별로 다릅니다. 이것이 타사 라이브러리가 필요한 이유입니다.
— kraxor

9
@kraxor 예, Windows에서만 작동하지만 OP는 크로스 플랫폼 솔루션을 요구하지 않습니다. BTW, 나는 항상 3 라이브러리를 사용하지 않고 무언가를 선택하는 것을 선호합니다 (가능한 경우).
— herohuyongtao

7
@herohuyongtao OP는 플랫폼을 지정하지 않았으며 일반적인 질문에 대한 플랫폼 의존적 솔루션을 제공하는 것은 오해의 소지가 있습니다. (PlayStation 3에서만 작동하는 단선 솔루션이 있다면 어떨까요? 여기에 정답입니까?) Windows에서만 작동한다는 답변을 편집 한 것 같습니다.이 방법으로는 문제가 없습니다.
— kraxor

1
@herohuyongtao OP는 그가 ls를 구문 분석 할 수 없다고 언급했으며 아마도 유닉스에있을 것입니다. 어쨌든 Windows에 대한 좋은 대답입니다.
— 토마스

2
나는를 사용하여 결국 std::vector<std::wstring>다음과 fileName.c_str()컴파일하지 않을 문자열의 벡터, 대신.
— PerryC

51

C 전용 솔루션의 경우이를 확인하십시오. 추가 헤더 만 필요합니다.

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

다른 옵션에 비해 몇 가지 장점 :

  • 이식성-POSIX dirent 및 Windows FindFirstFile 포장
  • 사용 readdir_r가능한 곳에서 사용 합니다 . 즉, 일반적으로 스레드 안전
  • 동일한 UNICODE매크로 를 통해 Windows UTF-16 지원
  • C90이므로 아주 오래된 컴파일러조차도 사용할 수 있습니다.

2
아주 좋은 제안입니다. 아직 Windows 컴퓨터에서 테스트하지는 않았지만 OS X에서 훌륭하게 작동합니다.
— ArtOfWarfare

라이브러리는 std :: string을 지원하지 않으므로 file.c_str ()을 tinydir_open에 전달할 수 없습니다. 이 경우 msvc 2015에서 컴파일하는 동안 오류 C2664가 발생합니다.
— Stepan Yakovenko

33

glob이 재사용 가능한 래퍼와 함께 사용 하는 것이 좋습니다 . vector<string>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;
}

다음과 같은 일반적인 시스템 와일드 카드 패턴으로 호출 할 수 있습니다.

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

2
glob ()가 0을 리턴하는지 테스트하십시오.
— Camille Goudeseune

당신이 추천 한대로 glob.h를 사용하고 싶습니다. 그러나 여전히 .h 파일을 포함시킬 수 없습니다 No such file or directory. 이 문제를 해결하는 방법을 알려주시겠습니까?
— Tofuw February

이 루틴은 한 수준 수준으로 만 진행됩니다 (재귀 없음). 또한 파일 또는 디렉토리인지 확인하기 위해 빠른 검사를 수행하지 않으며 슬래시로 끝나는 경로를 전환 한 다음 확인 GLOB_TILDE하여 쉽게 수행 할 수 있습니다 GLOB_TILDE | GLOB_MARK. 필요한 경우 수정해야합니다.
— Volomike

이 크로스 플랫폼 호환 가능합니까?
— Nikhil Augustine

불행히도를 통해 균일하게 숨겨진 파일을 찾을 수 없습니다 glob.
— LmTinyToon

23

다음은 라이브러리를 C++11사용하여 boost::filesystem디렉토리에서 파일 이름을 가져 오는 매우 간단한 코드입니다 (폴더 이름 제외).

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

출력은 다음과 같습니다

file1.txt
file2.dat

안녕하세요,이 라이브러리는 어디서 구할 수 있습니까?
— Alexander Leon VI

2
@Alexander 드 레온 : 당신은 자신의 사이트에서이 라이브러리를 얻을 수 있습니다 boost.org , 그들의 사용, 처음 시작 설명서 읽어 boost::filesystem라이브러리 boost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htm
— 나쁜

23

왜 사용하지 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;
}

필요한 포함을 설명하면 더 나은 대답이 될 수 있습니다.
— Volomike

2
glob ()가 0을 리턴하는지 테스트하십시오!
— orbitcowboy

* .txt와 같은 파일을 알고있을 때 유용합니다.
— Kemin Zhou

20

아래 스 니펫을 사용하여 모든 파일을 나열 할 수 있다고 생각합니다.

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

다음은 struct 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 */
};

나는 이것을 원합니다.
— selfboot

10

x- 플랫폼 방법으로 부스트 시도

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

또는 OS 특정 파일을 사용하십시오.


이 링크가 질문에 대한 답변을 제공 할 수 있지만 여기에 답변의 필수 부분을 포함시키고 참조 용 링크를 제공하는 것이 좋습니다. 링크 된 페이지가 변경되면 링크 전용 답변이 유효하지 않을 수 있습니다. - 리뷰에서
— ice1000

@ ice1000 진심으로? 이 Q & A는 2009 년
— Tim

8

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

GNU 매뉴얼 FTW

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

또한 때로는 소스로 바로 이동하는 것이 좋습니다 (말장난 의도). Linux에서 가장 일반적인 명령 중 일부를 살펴보면 많은 것을 배울 수 있습니다. github (읽기 위해)에 GNU의 coreutils에 대한 간단한 미러를 설정했습니다.

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

아마도 이것은 Windows를 해결하지는 않지만 이러한 방법을 사용하여 Unix 변형을 사용하는 경우가 많이있을 수 있습니다.

희망이 도움이 ...


5

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

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

3

이 코드가 도움이 되길 바랍니다.

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

4
-1. string2wchar_t지역 변수의 주소를 반환합니다. 또한 WinAPI에서 사용 가능한 변환 방법을 직접 작성하는 대신 사용해야합니다.
— Daniel Kamil Kozar

3

이 구현은 지정된 디렉토리의 내용으로 문자열 배열을 동적으로 채우는 목적을 실현합니다.

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

이것을 어떻게 부를까요? 첫 번째 if블록 에서이 기능을 실행하려고하면 segfault가 발생 합니다. 나는 그것을 부르고있다char **list; int numItems; exploreDirectory("/folder",list, numItems);
— Hal T

2

이것은 나를 위해 작동합니다. 출처를 기억할 수 없다면 죄송합니다. 아마 맨 페이지에서 온 것입니다.

#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

std :: experimental :: 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

이 답변은 다른 답변으로 Visual Studio를 사용하는 데 문제가있는 Windows 사용자에게 효과적입니다.

  1. github 페이지에서 dirent.h 파일을 다운로드하십시오. 그러나 Raw dirent.h 파일을 사용하고 아래 단계를 따르는 것이 좋습니다 (작동 방식).

    Windows 용 dirent.h에 대한 Github 페이지 : Github 페이지 Github 페이지

    원시 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

시스템 호출!

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

그런 다음 파일을 읽으십시오.

편집 :이 답변은 핵으로 간주되어야하지만보다 우아한 솔루션에 액세스 할 수없는 경우 실제로 플랫폼별로 작동하지만 실제로 작동합니다.


7
'ls'명령을 실행하고 프로그램 내에서 결과를 구문 분석 할 수 없습니다. 이런 식으로 보낼 사람이있을 줄
— 알았는데

1

디렉토리의 파일과 하위 디렉토리는 일반적으로 트리 구조로 저장되므로 직관적 인 방법은 DFS 알고리즘을 사용하여 각 파일을 재귀 적으로 순회하는 것입니다. 다음은 io.h의 기본 파일 기능을 사용하는 Windows 운영 체제의 예입니다. 다른 플랫폼에서 이러한 기능을 대체 할 수 있습니다. 내가 표현하고자하는 것은 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);
}

1

나는 두 대답 모두에 주어진 예를 따르려고 시도 std::filesystem::directory_entry했으며 <<연산자 의 과부하가없는 것으로 변경된 것처럼 보일 수도 있습니다 . 대신 std::cout << p << std::endl;컴파일하고 작동 시키려면 다음을 사용해야했습니다.

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

p자체 전달하려고하면 std::cout <<과부하 오류가 발생했습니다.


1

herohuyongtao가 게시 한 내용과 몇 가지 다른 게시물을 기반으로 :

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

FindFirstFile의 예상 입력 유형은 무엇입니까?

wstring을 문자열로 변환하는 방법은 무엇입니까?

이것은 Windows 솔루션입니다.

std :: string을 전달하고 문자열 벡터를 반환하고 싶었으므로 몇 가지 변환을해야했습니다.

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

멀티 바이트 만 사용한다는 것을 알고 있다면 WIN32_FIND_DATAA, FindFirstFileA및을 사용할 수 있습니다 FindNextFileA. 그러면 결과를 멀티 바이트로 변환하거나 입력을 유니 코드로 변환 할 필요가 없습니다.
— Kiran Thilak

0

독서 자료에 대해 공유하고 감사하게 생각하는 것입니다. 조금 이해하기 위해 기능을 가지고 놀아보십시오. 당신은 그것을 좋아할 것입니다. e는 확장, p는 경로, s는 경로 구분 기호입니다.

끝 구분 기호없이 경로를 전달하면 구분 기호가 경로에 추가됩니다. 확장자의 경우, 빈 문자열이 입력되면 함수는 이름에 확장자가없는 파일을 리턴합니다. 별표 하나가 입력 된 경우 디렉토리의 모든 파일이 반환됩니다. e 길이가 0보다 크지 만 단일 *가 아닌 경우 e가 0 위치에 점을 포함하지 않은 경우 점 앞에 e가 추가됩니다.

반환 값 길이가 0 인 맵이 리턴되면 아무것도 발견되지 않았지만 디렉토리는 열렸습니다. 인덱스 999가 리턴 값에서 사용 가능하지만 맵 크기가 1 인 경우 디렉토리 경로를 여는 데 문제점이 있음을 의미합니다.

효율성을 위해이 기능을 3 개의 작은 기능으로 나눌 수 있습니다. 또한 입력을 기반으로 호출 할 함수를 감지하는 호출자 함수를 작성할 수 있습니다. 왜 더 효율적입니까? 파일 인 모든 것을 잡으려고한다면, 그 방법을 사용하면 모든 파일을 잡기 위해 만들어진 하위 함수는 파일 인 모든 것을 잡아서 파일을 찾을 때마다 다른 불필요한 조건을 평가할 필요가 없습니다.

확장명이없는 파일을 가져올 때에도 적용됩니다. 해당 목적을위한 특정 내장 함수는 찾은 객체가 파일 인 경우 날씨에 대해서만 평가 한 다음 파일 이름에 점이 있는지 여부를 평가합니다.

파일이 많지 않은 디렉토리 만 읽으면 저장량이 그리 많지 않을 수 있습니다. 그러나 대량의 디렉토리를 읽거나 디렉토리에 수십만 개의 파일이있는 경우 크게 절약 할 수 있습니다.

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

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

-1

이것은 나를 위해 일했습니다. 모든 파일의 이름 (경로 없음)으로 파일을 작성합니다. 그런 다음 해당 txt 파일을 읽고 인쇄합니다.

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

    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.