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

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

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



답변

작고 간단한 작업에서 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;
}

답변

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서브 디렉토리도 반복 할 수 있습니다.


답변

불행히도 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 페이지의 소스 코드


답변

하나의 기능만으로도 타사 라이브러리 (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-파일을 얻기 위해 (즉, 특정 유형의)에서.


답변

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이므로 아주 오래된 컴파일러조차도 사용할 수 있습니다.

답변

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

답변

다음은 라이브러리를 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