Bagaimana saya bisa mendapatkan daftar file dalam direktori menggunakan C atau C ++?


593

Bagaimana saya bisa menentukan daftar file dalam direktori dari dalam kode C atau C ++ saya?

Saya tidak diizinkan untuk mengeksekusi lsperintah dan mem-parsing hasil dari dalam program saya.


7
Ini adalah duplikat dari 609236
chrish


1
@ Chish - Ya tapi yang ini memiliki klasik "Saya tidak diizinkan mengeksekusi 'ls'"! Ini persis bagaimana saya akan merasa tahun 1 Ilmu Komputer. ; D <3 x
James Bedford

1
C dan C ++ bukan bahasa yang sama. Oleh karena itu, prosedur untuk menyelesaikan tugas ini akan berbeda dalam kedua bahasa. Silakan pilih satu dan beri tag ulang sesuai.
MD XF

2
Dan tak satu pun dari bahasa tersebut (selain C ++ sejak C ++ 17) bahkan memiliki konsep direktori - jadi jawaban apa pun kemungkinan bergantung pada OS Anda, atau pada pustaka abstraksi apa pun yang mungkin Anda gunakan.
Toby Speight

Jawaban:


809

Dalam tugas-tugas kecil dan sederhana saya tidak menggunakan boost, saya menggunakan dirent.h yang juga tersedia untuk 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;
}

Ini hanya file header kecil dan melakukan sebagian besar hal-hal sederhana yang Anda butuhkan tanpa menggunakan pendekatan berbasis template besar seperti boost (jangan tersinggung, saya suka boost!).

Penulis lapisan kompatibilitas windows adalah Toni Ronkko. Di Unix, itu adalah header standar.

PEMBARUAN 2017 :

Dalam C ++ 17 sekarang ada cara resmi untuk daftar file dari sistem file Anda: std::filesystem. Ada jawaban yang sangat baik dari Shreevardhan di bawah ini dengan kode sumber ini:

#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 bahkan tidak dibuat ketika pertanyaan ini dijawab. Juga itu adalah pembungkus di sekitar dirent (POSIX) dan FindFirstFile (Windows), sementara dirent.h hanya membungkus dirent untuk windows. Saya pikir itu adalah selera pribadi, tetapi dirent.h terasa lebih sebagai standar
Peter Parker

7
@JoshC: karena * ent hanyalah pointer yang dikembalikan dari representasi internal. dengan menutup direktori Anda akan menghilangkan * ent juga. Karena * ent hanya untuk membaca, saya rasa ini adalah desain yang waras.
Peter Parker

42
orang jadi nyata !! ini adalah pertanyaan dari tahun 2009 dan bahkan belum disebutkan VS. Jadi jangan mengkritik bahwa IDE milik Anda (walaupun cukup bagus) tidak mendukung standar OS lama. Juga jawaban saya mengatakan itu "tersedia" untuk windows, tidak "termasuk" dalam IDE apa pun dari sekarang dan setiap saat ... Saya cukup yakin Anda dapat mengunduh dirent dan memasukkannya ke dalam beberapa direktori termasuk dir dan voila itu ada.
Peter Parker

6
Jawabannya menyesatkan. Itu harus dimulai dengan: " ... Saya menggunakan dirent.h , di mana lapisan kompatibilitas open-source Windows juga ada ".
rustyx

10
Dengan C ++ 14 ada std::experimental::filesystem, dengan C ++ 17 ada std::filesystem. Lihat jawaban Shreevardhan di bawah ini. Jadi tidak perlu untuk perpustakaan pihak ke-3.
Roi Danton

347

C ++ 17 sekarang memiliki std::filesystem::directory_iterator, yang dapat digunakan sebagai

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

Juga, std::filesystem::recursive_directory_iteratordapat mengulangi subdirektori juga.


28
AFAIK juga dapat digunakan dalam C ++ 14, tapi ada masih eksperimental: namespace fs = std::experimental::filesystem;. Tampaknya berfungsi ok.
PeterK

7
Ini harus menjadi jawaban yang lebih disukai untuk penggunaan saat ini (dimulai dengan C ++ 17)
green diod

4
Mengindahkan ketika melewati std::filesystem::pathke std::cout, tanda kutip termasuk dalam output. Untuk menghindarinya, tambahkan .string()jalur untuk melakukan konversi eksplisit dan bukan implisit (di sini std::cout << p.string() << std::endl;). Contoh: coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3
Roi Danton

2
Bagaimana dengan karakter NON-ASCII dalam nama file? Tidak std::wstringboleh digunakan atau apa jenis dari iterator?
anddero

2
Saya tidak yakin apakah saya sendirian dalam hal ini, tetapi tanpa menghubungkan ke -lstdc++fs, saya akan mendapatkan SIGSEGV (Address boundary error). Saya tidak dapat menemukan di mana pun dalam dokumentasi bahwa ini diperlukan, dan tautan tidak memberikan petunjuk apa pun. Ini bekerja untuk keduanya g++ 8.3.0dan clang 8.0.0-3. Apakah ada yang punya wawasan ke mana hal-hal seperti ini ditentukan dalam dokumen / spesifikasi?
swalog

229

Sayangnya standar C ++ tidak mendefinisikan cara standar untuk bekerja dengan file dan folder dengan cara ini.

Karena tidak ada cara lintas platform, cara lintas platform terbaik adalah dengan menggunakan perpustakaan seperti modul sistem file boost .

Metode peningkatan lintas platform:

Fungsi berikut, diberi jalur direktori dan nama file, secara rekursif mencari direktori dan sub-direktori untuk nama file, mengembalikan bool, dan jika berhasil, path ke file yang ditemukan.

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

Sumber dari halaman boost yang disebutkan di atas.

Untuk sistem berbasis Unix / Linux:

Anda dapat menggunakan opendir / readdir / closedir .

Kode sampel yang mencari direktori untuk entri `` name '' adalah:

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;

Kode sumber dari halaman manual di atas.

Untuk sistem berbasis windows:

Anda dapat menggunakan fungsi Win32 API FindFirstFile / FindNextFile / FindClose .

Contoh C ++ berikut ini menunjukkan kepada Anda penggunaan FindFirstFile yang minimal.

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

Kode sumber dari halaman msdn di atas.


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

7
Dengan C ++ 14 ada std::experimental::filesystem, dengan C ++ 17 ada std::filesystem, yang memiliki fungsi yang sama dengan boost (libs berasal dari boost). Lihat jawaban Shreevardhan di bawah ini.
Roi Danton


90

Satu fungsi sudah cukup, Anda tidak perlu menggunakan perpustakaan pihak ke-3 (untuk 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: seperti yang disebutkan oleh @Sebastian, Anda bisa mengubah *.*ke *.extuntuk mendapatkan hanya file EXT (yaitu dari jenis tertentu) di direktori itu.


20
Solusi ini jika spesifik platform. Itulah alasan Anda membutuhkan perpustakaan pihak ketiga.
kraxor

9
@ kraxor Ya, itu hanya bekerja di Windows, tetapi OP tidak pernah meminta untuk memiliki solusi lintas platform. BTW, saya selalu memilih untuk memilih sesuatu tanpa menggunakan perpustakaan ke-3 (jika mungkin).
herohuyongtao

7
@herohuyongtao OP tidak pernah menentukan platform, dan memberikan solusi yang sangat tergantung platform untuk pertanyaan umum bisa menyesatkan. (Bagaimana jika ada solusi satu baris yang hanya berfungsi di PlayStation 3? Apakah itu jawaban yang bagus di sini?) Saya melihat Anda mengedit jawaban Anda untuk menyatakan bahwa itu hanya berfungsi pada Windows, saya kira tidak apa-apa dengan cara ini.
kraxor

1
@herohuyongtao OP menyebutkan dia tidak dapat menguraikan ls, artinya dia mungkin menggunakan unix .. bagaimanapun, jawaban yang bagus untuk Windows.
Thomas

2
Saya akhirnya menggunakan std::vector<std::wstring>dan fileName.c_str()bukannya vektor string, yang tidak akan dikompilasi.
PerryC

51

Untuk solusi C saja, silakan periksa ini. Hanya membutuhkan tajuk tambahan:

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

Beberapa keunggulan dibandingkan opsi lain:

  • Ini portabel - membungkus diriny POSIX dan Windows FindFirstFile
  • Itu menggunakan readdir_rmana tersedia, yang berarti itu (biasanya) threadsafe
  • Mendukung Windows UTF-16 melalui UNICODEmakro yang sama
  • Ini adalah C90 sehingga bahkan kompiler yang sangat kuno dapat menggunakannya

2
Saran yang sangat bagus. Saya belum mengujinya di komputer windows tetapi ia bekerja dengan sangat baik pada OS X.
ArtOfWarfare

Perpustakaan tidak mendukung std :: string, jadi Anda tidak dapat meneruskan file.c_str () ke tinydir_open. Ini memberikan kesalahan C2664 selama kompilasi pada msvc 2015 dalam hal ini.
Stepan Yakovenko

33

Saya sarankan menggunakan globpembungkus yang dapat digunakan kembali ini. Ini menghasilkan yang vector<string>sesuai dengan jalur file yang sesuai dengan pola 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;
}

Yang kemudian dapat dipanggil dengan pola wildcard sistem normal seperti:

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

2
Uji bahwa glob () mengembalikan nol.
Camille Goudeseune

Saya ingin menggunakan glob.h seperti yang Anda rekomendasikan. Tapi tetap saja, saya tidak bisa memasukkan file .h: Dikatakan No such file or directory. Bisakah Anda memberi tahu saya cara mengatasi masalah ini?
Tofuw

Perhatikan bahwa rutin ini hanya memiliki kedalaman satu tingkat (tanpa rekursi). Itu juga tidak melakukan pemeriksaan cepat untuk menentukan apakah itu file atau direktori, yang dapat Anda lakukan dengan mudah dengan beralih GLOB_TILDEdengan GLOB_TILDE | GLOB_MARKdan kemudian memeriksa jalur yang berakhir dengan garis miring. Anda harus membuat modifikasi untuk itu jika Anda membutuhkannya.
Volomike

Apakah cross-platform ini kompatibel?
Nikhil Augustine

Sayangnya Anda tidak dapat menemukan file yang disembunyikan secara seragam melalui glob.
LmTinyToon

23

Berikut ini adalah kode yang sangat sederhana dalam C++11menggunakan boost::filesystemperpustakaan untuk mendapatkan nama file dalam direktori (tidak termasuk nama folder):

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

Outputnya seperti:

file1.txt
file2.dat

Hai, dan di mana saya bisa mendapatkan perpustakaan ini?
Alexander Leon VI

2
@Alexander De Leon: Anda bisa mendapatkan perpustakaan ini di situs mereka boost.org , baca panduan memulai terlebih dahulu, kemudian gunakan boost::filesystemperpustakaan boost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htm
Buruk

23

Kenapa tidak digunakan 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;
}

Ini bisa menjadi jawaban yang lebih baik jika Anda menjelaskan termasuk yang diperlukan.
Volomike

2
Uji bahwa glob () mengembalikan nol!
orbitcowboy

Ini bagus ketika Anda tahu file yang Anda cari seperti * .txt
Kemin Zhou

20

Saya pikir, cuplikan di bawah ini dapat digunakan untuk mendaftar semua file.

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

Berikut ini adalah struktur dari 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 */
};

Saya mau yang ini.
Selfboot


8

Lihat kelas ini yang menggunakan api win32. Cukup buat instance dengan menyediakan foldernamedari mana Anda ingin listing kemudian panggil getNextFilemetode untuk mendapatkan yang berikutnya filenamedari direktori. Saya pikir itu perlu windows.hdan 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

Manual GNU FTW

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

Juga, kadang-kadang ada baiknya langsung ke sumbernya (pun intended). Anda dapat belajar banyak dengan melihat jeroan dari beberapa perintah yang paling umum di Linux. Saya telah membuat mirror sederhana dari GNU's coreutils di github (untuk membaca).

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

Mungkin ini tidak membahas Windows, tetapi sejumlah kasus menggunakan varian Unix dapat diperoleh dengan menggunakan metode ini.

Semoga itu bisa membantu ...


5

Jawaban Shreevardhan bekerja dengan sangat baik. Tetapi jika Anda ingin menggunakannya di c ++ 14, lakukan saja perubahannamespace fs = experimental::filesystem;

yaitu,

#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

Saya harap kode ini membantu Anda.

#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_tmengembalikan alamat variabel lokal. Juga, Anda mungkin harus menggunakan metode konversi yang tersedia di WinAPI alih-alih menulis metode Anda sendiri.
Daniel Kamil Kozar

3

Implementasi ini mewujudkan tujuan Anda, secara dinamis mengisi serangkaian string dengan konten direktori yang ditentukan.

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

Bagaimana saya menyebutnya? Saya mendapatkan segfault ketika saya mencoba menjalankan fungsi ini di ifblok pertama . Saya menyebutnya denganchar **list; int numItems; exploreDirectory("/folder",list, numItems);
Hal T

2

Ini bekerja untuk saya. Maaf jika saya tidak dapat mengingat sumbernya. Mungkin dari halaman manual.

#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

Anda bisa mendapatkan semua file langsung di direktori root Anda dengan menggunakan std :: experimental :: filesystem :: directory_iterator (). Kemudian, baca nama pathfiles ini.

#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

Jawaban ini seharusnya berfungsi untuk pengguna Windows yang mengalami kesulitan dalam menjalankan ini dengan Visual Studio dengan jawaban lain mana pun.

  1. Unduh file dirent.h dari halaman github. Tetapi lebih baik hanya menggunakan file Raw dirent.h dan ikuti langkah-langkah saya di bawah ini (ini adalah cara saya membuatnya bekerja).

    Halaman Github untuk dirent.h untuk Windows: Halaman Github untuk dirent.h

    Raw Dirent File: Raw dirent.h File

  2. Buka proyek Anda dan Tambahkan Item baru ( Ctrl+ Shift+ A). Tambahkan file header (.h) dan beri nama dirent.h.

  3. Tempel kode file Raw dirent.h ke dalam header Anda.

  4. Sertakan "dirent.h" dalam kode Anda.

  5. Masukkan void filefinder()metode di bawah ini dalam kode Anda dan panggil dari mainfungsi Anda atau edit fungsi bagaimana Anda ingin menggunakannya.

    #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

Sebut saja sistem itu!

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

Kemudian baca saja file tersebut.

EDIT: Jawaban ini harus dianggap sebagai peretasan, tetapi ini benar-benar berfungsi (walaupun dengan cara khusus platform) jika Anda tidak memiliki akses ke solusi yang lebih elegan.


7
Saya tidak diizinkan untuk menjalankan perintah 'ls' dan menguraikan hasil dari dalam program saya. Saya tahu akan ada seseorang yang akan mengirim sesuatu seperti ini ...
yyny

1

Karena file dan sub direktori direktori umumnya disimpan dalam struktur pohon, cara intuitif adalah dengan menggunakan algoritma DFS untuk secara rekursif melintasi masing-masing. Berikut adalah contoh dalam sistem operasi windows dengan menggunakan fungsi file dasar di io.h. Anda dapat mengganti fungsi-fungsi ini di platform lain. Yang ingin saya ungkapkan adalah bahwa ide dasar DFS memenuhi masalah ini dengan sempurna.

#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

Saya mencoba mengikuti contoh yang diberikan di kedua jawaban dan mungkin perlu dicatat bahwa tampaknya seolah-olah std::filesystem::directory_entrytelah diubah untuk tidak memiliki kelebihan <<operator. Alih-alih std::cout << p << std::endl;saya harus menggunakan yang berikut ini untuk dapat mengkompilasi dan membuatnya berfungsi:

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

mencoba meneruskan psendiri untuk std::cout <<menghasilkan kesalahan kelebihan yang hilang.


1

Membangun apa yang diposting oleh herohuyongtao dan beberapa posting lainnya:

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

Apa tipe input yang diharapkan dari FindFirstFile?

Bagaimana cara mengubah wstring menjadi string?

Ini adalah solusi Windows.

Karena saya ingin meneruskan std :: string dan mengembalikan vektor string, saya harus membuat beberapa konversi.

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

Jika Anda tahu bahwa Anda hanya akan menggunakan multibyte, Anda dapat menggunakan WIN32_FIND_DATAA, FindFirstFileAdan FindNextFileA. Maka Tidak perlu mengubah hasil menjadi multibyte atau Input ke unicode.
Kiran Thilak

0

Hanya sesuatu yang ingin saya bagikan dan terima kasih atas bahan bacaannya. Bermain-main dengan fungsi untuk sedikit memahaminya. Anda mungkin menyukainya. e berdiri untuk ekstensi, p adalah untuk path, dan s adalah untuk path separator.

Jika jalur dilewatkan tanpa mengakhiri pemisah, pemisah akan ditambahkan ke jalur. Untuk ekstensi, jika string kosong dimasukkan maka fungsi akan mengembalikan file apa pun yang tidak memiliki ekstensi dalam namanya. Jika satu bintang dimasukkan dari semua file dalam direktori akan dikembalikan. Jika panjang e lebih besar dari 0 tetapi bukan satu * maka titik akan ditambahkan ke e jika e tidak mengandung titik di posisi nol.

Untuk nilai kembali. Jika peta nol panjang dikembalikan maka tidak ada yang ditemukan tetapi direktori terbuka oke. Jika indeks 999 tersedia dari nilai kembali tetapi ukuran peta hanya 1 maka itu berarti ada masalah dengan membuka jalur direktori.

Perhatikan bahwa untuk efisiensi, fungsi ini dapat dibagi menjadi 3 fungsi yang lebih kecil. Selain itu, Anda dapat membuat fungsi pemanggil yang akan mendeteksi fungsi mana yang akan dipanggil berdasarkan input. Mengapa itu lebih efisien? Mengatakan jika Anda akan mengambil semua yang merupakan file, melakukan metode itu subfungsi yang dibangun untuk mengambil semua file hanya akan mengambil semua file dan tidak perlu mengevaluasi kondisi lain yang tidak perlu setiap kali ditemukan file.

Itu juga berlaku ketika Anda mengambil file yang tidak memiliki ekstensi. Fungsi dibangun khusus untuk tujuan itu hanya akan mengevaluasi cuaca jika objek yang ditemukan adalah file dan kemudian apakah nama file memiliki titik di dalamnya.

Penghematan mungkin tidak banyak jika Anda hanya membaca direktori dengan tidak banyak file. Tetapi jika Anda membaca sejumlah besar direktori atau jika direktori tersebut memiliki beberapa ratus ribu file, ini bisa menjadi penghematan besar.

#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

Ini berhasil untuk saya. Itu menulis file dengan hanya nama (tidak ada jalur) dari semua file. Kemudian ia membaca file txt itu dan mencetaknya untuk Anda.

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

    }
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.