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.

samoz
sumber
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;
}
Peter Parker
sumber
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.

Shreevardhan
sumber
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.

Brian R. Bondy
sumber
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
Untuk windows, lihat docs.microsoft.com/en-us/windows/desktop/FileIO/… untuk detail
FindOutIslamNow
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.

herohuyongtao
sumber
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
congusbongus
sumber
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("./*");
Chris Redford
sumber
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
Buruk
sumber
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;
}
Meekohi
sumber
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 */
};
Bersyukur
sumber
Saya mau yang ini.
Selfboot
10

Coba tingkatkan untuk metode x-platform

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

atau cukup gunakan file hal spesifik OS Anda.

Tim
sumber
Meskipun tautan ini dapat menjawab pertanyaan, lebih baik untuk memasukkan bagian-bagian penting dari jawaban di sini dan memberikan tautan untuk referensi. Jawaban hanya tautan dapat menjadi tidak valid jika halaman tertaut berubah. - Dari Ulasan
ice1000
@ ice1000 Serius? T&J ini dari 2009
Tim
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;
    }

};
robertvarga
sumber
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 ...

Homer6
sumber
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;
}
Venkat Vinay
sumber
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;
}
JasonYen2205
sumber
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;
}
Yas
sumber
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;
}
Giacomo Marciani
sumber
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/");
}
MENARIK
sumber
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;
}
ducPham
sumber
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);
    }
ZKR
sumber
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.

Katalisator
sumber
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);
}
tkingcer
sumber
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.

StarKiller4011
sumber
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;
}
tzg
sumber
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;
}
Kevin Ng
sumber
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;
}
Stan Sokolov
sumber
-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;
        }

    }
Cesar Alejandro Montero Orozco
sumber