CまたはC ++を使用してディレクトリ内のファイルのリストを取得するにはどうすればよいですか?


593

CまたはC ++コード内からディレクトリ内のファイルのリストを確認するにはどうすればよいですか?

lsコマンドを実行して、プログラム内から結果を解析することはできません。


7
これは609236の
09年


1
@chrish-ええ、でもこれには「私は 'ls'を実行することはできません」という古典があります!それはまさに私がコンピュータサイエンスの1年目を感じる方法です。; D <3 x
James Bedford

1
CとC ++は同じ言語ではありません。したがって、このタスクを実行する手順は、両方の言語で異なります。いずれかを選択し、それに応じてタグを付け直してください。
MD XF 2017年

2
また、これらの言語(C ++ 17以降のC ++以外)のいずれにもディレクトリの概念はありません。そのため、回答はOSまたは使用している抽象化ライブラリに依存している可能性があります。
Toby Speight

回答:


809

小さくて単純なタスクでは、ブーストを使用しません。dirent.hを使用します。これはWindowsでも使用できます。

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

これは小さなヘッダーファイルであり、ブーストなどの大きなテンプレートベースのアプローチを使用せずに、必要なシンプルなほとんどのことを実行します(違反なし、私はブーストが好きです!)。

Windows互換性レイヤーの作成者はToni Ronkkoです。Unixでは、これは標準ヘッダーです。

更新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フィール
ピーター・パーカー

7
@JoshC:* entは内部表現の返されたポインタにすぎないため。ディレクトリを閉じると、* entも削除されます。* entは読み取り専用であるため、これは正気なデザインだと思います。
Peter Parker

42
人々は本物になります!これは2009年からの質問であり、VSについてさえ言及していません。したがって、完全に独自の(かなり良いものの)IDEが何世紀も前のOS標準をサポートしていないことを批判しないでください。また、私の回答では、これはWindowsで「利用可能」であり、これからはどのIDEにも「含まれる」わけではありません。
Peter Parker

6
答えは誤解を招くものです。「...私はdirent.hを使用します。これには、Windowsオープンソース互換性レイヤーも存在します」。
rustyx

10
C ++ 14にはstd::experimental::filesystemC ++ 17がありstd::filesystemます。以下のShreevardhanの回答を参照してください。したがって、サードパーティのライブラリは必要ありません。
Roi Danton 2017

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以降)で推奨される答えです
緑のdiod

4
渡すときに留意がstd::filesystem::pathstd::cout、引用符は出力に含まれています。これを回避する.string()には、暗黙的な変換ではなく明示的な変換を行うためにパスに追加します(ここstd::cout << p.string() << std::endl;)。例:coliru.stacked-crooked.com/view?id
Roi Danton

2
ファイル名の非ASCII文字についてはどうですか?std::wstring使用すべきではないか、イテレータからの型は何ですか?
anddero

2
私はこれで一人であるかどうかはわかりませんが、にリンクしないと-lstdc++fs、を取得しSIGSEGV (Address boundary error)ます。ドキュメントでこれが必要な場所を見つけることができず、リンカも手掛かりを与えませんでした。これはとの両方g++ 8.3.0で機能しましたclang 8.0.0-3。このようなものがdocs / specsで指定されている場所についての洞察は誰にもありますか?
swalog

229

残念ながら、C ++標準では、この方法でファイルやフォルダーを操作する標準的な方法を定義していません。

クロスプラットフォームの方法がないため、最適なクロスプラットフォームの方法は、boostファイルシステムモジュールなどのライブラリを使用することです

クロスプラットフォームのブースト方法:

次の関数は、ディレクトリパスとファイル名が指定されると、ディレクトリとそのサブディレクトリでファイル名を再帰的に検索し、boolを返します。成功した場合は、見つかったファイルへのパスを返します。

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

上記のブーストページからのソース。

Unix / Linuxベースのシステムの場合:

opendir / readdir / closedirを使用できます。

ディレクトリでエントリ「名前」を検索するサンプルコードは次のとおりです:

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;

上記のmanページのソースコード。

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::filesystem。これは、boostと同様の機能を備えています(libはboostから派生しています)。以下のShreevardhanの回答を参照してください。
Roi Danton 2017

Windowsの場合、詳細についてはdocs.microsoft.com/en-us/windows/desktop/FileIO/…を参照してください
FindOutIslamNow

90

1つの機能で十分です。サードパーティのライブラリ(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:@Sebastianで述べたように、あなたは変更される可能性*.**.extそのディレクトリ内のみEXT-ファイル(すなわち、特定のタイプの)を得るために。


20
このソリューションは、プラットフォーム固有です。これが、サードパーティのライブラリが必要な理由です。
Kraxor

9
@kraxorはい、それはWindowsでのみ機能しますが、OPはクロスプラットフォームソリューションを要求しません。ところで、私は常に(可能であれば)第3ライブラリを使用せずに何かを選ぶことを好みます。
herohuyongtao 2014年

7
@herohuyongtao OPはプラットフォームを指定したことがなく、一般的な質問に対してプラットフォームに大きく依存するソリューションを提供することは誤解を招く可能性があります。(PlayStation 3でのみ機能する1行のソリューションがある場合はどうでしょうか?これは良い答えですか?)Windowsでのみ機能するという回答を編集したようですが、この方法で問題ないと思います。
Kraxor

1
@herohuyongtao OPは、lsを解析できないと述べました。つまり、彼はおそらくUNIX上にいるということです。とにかく、Windowsには良い答えです。
トーマス

2
最終的に、コンパイルされない文字列のベクトルの代わりにa を使用することに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ての(通常は)スレッドセーフを意味し、利用可能な場合
  • 同じ経由でWindows UTF-16をサポート UNICODEマクロを
  • これはC90なので、非常に古いコンパイラーでも使用できます

2
とてもいい提案です。私は、Windowsコンピュータ上でそれをテストしていませんが、まだそれはOS X上で見事に動作します
ArtOfWarfare

ライブラリはstd :: stringをサポートしていないため、file.c_str()をtinydir_openに渡すことはできません。この場合、msvc 2015でのコンパイル中にエラーC2664が発生します。
Stepan Yakovenko 2017年

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()がゼロを返すことをテストします。
Camille Goudeseune、2015年

私はあなたが推奨するようにglob.hを使用したいと思います。しかし、それでも、.hファイルを含めることはできませんNo such file or directory。この問題の解決方法を教えていただけますか?
Tofuw 2016

このルーチンは1レベルだけの深さであることに注意してください(再帰はありません)。また、それがファイルであるかディレクトリであるかを判断するためのクイックチェックは行われません。これは、スラッシュで終了するパスを切り替えGLOB_TILDEGLOB_TILDE | GLOB_MARK確認することで簡単に確認できます。必要に応じて、いずれかの変更を行う必要があります。
Volomike、2016年

これはクロスプラットフォーム互換ですか?
Nikhil Augustine

残念ながら、を介して均一に隠されたファイルを見つけることはできませんglob
LmTinyToon 2018年

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 De Leon:このライブラリは、サイトboost.orgで入手できます。最初にスタートガイドを読んでから、boost::filesystemライブラリboost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htmを
Bad

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、2016年

2
glob()がゼロを返すことをテストしてください!
orbitcowboy 2016年

これは、*。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 */
};

これお願いします。
セルフブート

10

x-platformメソッドのboostを試す

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

または、OS固有のファイルを使用するだけです。


このリンクで質問に答えることができますが、回答の重要な部分をここに含め、参照用のリンクを提供することをお勧めします。リンクされたページが変更されると、リンクのみの回答が無効になる可能性があります。- レビューから
ice1000

@ ice1000マジ?このQ&Aは2009年から
ティム

8

win32 apiを使用するこのクラスを確認してください。foldernameリストを作成したいfromを指定してインスタンスを作成し、次にgetNextFileメソッドを呼び出しfilenameてディレクトリから次を取得します。私はそれが必要だと思うwindows.hstdio.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で最も一般的なコマンドのいくつかの内部を見ることで、多くを学ぶことができます。GNUのcoreutilsの単純なミラーをgithubに設定しました(読み取り用)。

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

これはWindowsに対応していない可能性がありますが、これらの方法を使用することで、Unixバリアントを使用する多くのケースが発生する可能性があります。

お役に立てば幸い...


5

シュリーバーダンの答えはうまくいきます。しかし、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 2013年

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ブロックで実行しようとすると、セグメンテーション違反が発生します。私はそれを次のように呼んでいますchar **list; int numItems; exploreDirectory("/folder",list, numItems);
Hal T

2

これでうまくいきます。出所を思い出せなくてごめんなさい。おそらくmanページからのものです。

#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ページdirent.hのGithubページ

    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

システムはそれを呼び出します!

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

次に、ファイルを読み取ります。

編集:この回答はハックと見なされるべきですが、よりエレガントなソリューションにアクセスできない場合は、(プラットフォーム固有の方法ではありますが)本当に機能します。


7
'ls'コマンドを実行して、プログラム内から結果を解析することはできません。私はこのような何かを送る誰かがいることを知っていました...
yyny

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_DATAAFindFirstFileAおよびを使用できます FindNextFileA。その後、結果をマルチバイトに変換したり、入力をユニコードに変換したりする必要はありません。
キランティラク

0

私が共有したいと思うものだけであり、読書資料をありがとう。関数を少し理解して理解してください。あなたはそれを好きかもしれません。eは拡張子を表し、pはパスを表し、sはパスセパレータを表します。

終了セパレータなしでパスが渡されると、パスにセパレータが追加されます。拡張子については、空の文字列が入力された場合、関数は名前に拡張子がないファイルを返します。単一の星が入力された場合、ディレクトリ内のすべてのファイルが返されます。eの長さが0より大きいが単一の*ではない場合、eがゼロの位置にドットを含んでいなかった場合、ドットはeの前に付加されます。

戻り値の場合。長さゼロのマップが返された場合は、何も見つかりませんでしたが、ディレクトリは正常に開いていました。戻り値からインデックス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.