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::pathstd::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.