C veya C ++ kullanarak bir dizindeki dosyaların listesini nasıl alabilirim?


593

Bir dizindeki dosyaların listesini C veya C ++ kodumun içinden nasıl belirleyebilirim?

Ben yürütmek için izin yok lskomuta ve benim program içinden sonuçlarını ayrıştırmak.




1
@chrish - Evet ama bu klasik "Ben ls yürütmek için izin verilmez" vardır! Bu var tam olarak ben Bilgisayar Bilimleri 1 yıl hissederdim nasıl. ; D <3 x
James Bedford

1
C ve C ++ aynı dil değildir. Bu nedenle, bu görevi yerine getirme prosedürü her iki dilde de farklı olacaktır. Lütfen birini seçin ve uygun şekilde yeniden etiketleyin.
MD XF

2
Ve bu dillerden hiçbiri (C ++ 17'den beri C ++ dışında) bir dizin kavramına bile sahip değildir - bu nedenle herhangi bir cevabın işletim sisteminize veya kullanmakta olduğunuz herhangi bir soyutlama kütüphanesine bağlı olması muhtemeldir.
Toby Speight

Yanıtlar:


809

Küçük ve basit görevlerde boost kullanmıyorum, dirent.h kullanıyorum windows için de kullanılabilir :

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

Bu sadece küçük bir başlık dosyasıdır ve boost gibi büyük bir şablon tabanlı yaklaşım kullanmadan ihtiyacınız olan basit şeylerin çoğunu yapar (hücum yok, boost'u seviyorum!).

Windows uyumluluk katmanının yazarı Toni Ronkko'dur. Unix'te standart bir başlıktır.

GÜNCELLEME 2017 :

C ++ şimdi dosya sisteminin liste dosyalarına resmi bir yolu yoktur 17: std::filesystem. Shreevardhan'ın bu kaynak koduyla mükemmel bir cevabı var :

#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: Bu soru cevaplandığında tinydir bile oluşturulmadı. Ayrıca dirent.h sadece windows için dirent sararken, dirent (POSIX) ve FindFirstFile (Windows) etrafında bir sarıcıdır. Kişisel bir tat olduğunu düşünüyorum, ama dirent.h standart olarak daha fazla hissediyor
Peter Parker

7
@JoshC: çünkü * ent, dahili gösterimin yalnızca bir göstergesidir. dizini kapatarak * ent de ortadan kaldıracak. * Ent sadece okumak için olduğu için, bu bir aklı başında tasarım, bence.
Peter Parker

42
insanlar gerçek olsun !! Bu 2009'dan bir soru ve VS'den bile bahsetmedi. Bu nedenle, tam tescilli (oldukça hoş olmasına rağmen) IDE'nizin yüzyıllardır süren işletim sistemi standartlarını desteklemediğini eleştirmeyin. Ayrıca cevabım şimdi ve her zaman için herhangi bir IDE "dahil" değil pencereler için "kullanılabilir" dedi Ben dirent indirmek ve orada bazı dahil dir ve voila koymak eminim.
Peter Parker

6
Cevap yanıltıcıdır. Şununla başlamalıdır: " ... Windows açık kaynak uyumluluk katmanının da bulunduğu dirent.h kullanıyorum ".
rustyx

10
C ++ 14 std::experimental::filesystemile C ++ 17 ile vardır std::filesystem. Shreevardhan'ın cevabını aşağıda görebilirsiniz. Bu yüzden 3. taraf kütüphanelere gerek yok.
Roi Danton

347

C ++ 17 artık sahip std::filesystem::directory_iteratorolarak kullanılabilen,

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

Ayrıca, std::filesystem::recursive_directory_iteratoralt dizinleri de yineleyebilir.


28
AFAIK da C ++ 14 kullanılabilir, ama yine de deneysel vardır: namespace fs = std::experimental::filesystem;. Tamam olsa çalışıyor gibi görünüyor.
PeterK

7
Bu mevcut kullanım için tercih edilen cevap olmalıdır (C ++ 17 ile başlayan)
yeşil diod

4
Geçerken std::filesystem::pathdikkat edin std::cout, tırnak işaretleri çıktıya dahil edilir. Bundan kaçınmak için, .string()örtük bir dönüşüm yerine açık bir yol yapma yoluna ekleyin (burada std::cout << p.string() << std::endl;). Örnek: coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3
Roi Danton

2
Dosya adlarındaki NON-ASCII karakterleri ne olacak? Olmamalı std::wstringkullanılmış veya İlerleticiden tipi ne olabilir?
anddero

2
Bunda yalnız olup olmadığımdan emin değilim, ama bağlantı kurmadan -lstdc++fsbir tane alırdım SIGSEGV (Address boundary error). Belgede bunun gerekli olduğunu hiçbir yerde bulamadım ve bağlayıcı da herhangi bir ipucu vermedi. Bu hem g++ 8.3.0ve için çalıştı clang 8.0.0-3. Dokümanlar / spesifikasyonlarda böyle şeylerin nerede belirtildiğine dair herhangi bir görüş var mı?
swalog

229

Ne yazık ki C ++ standardı, dosya ve klasörlerle bu şekilde çalışmanın standart bir yolunu tanımlamaz.

Çapraz platform yolu olmadığından, en iyi çapraz platform yolu boost dosya sistemi modülü gibi bir kitaplık kullanmaktır .

Çapraz platform yükseltme yöntemi:

Bir dizin yolu ve dosya adı verilen aşağıdaki işlev, dizinde ve alt dizinlerinde özyinelemeli olarak dosya adını arar, bir bool döndürür ve başarılı olursa bulunan dosyanın yolunu arar.

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

Yukarıda belirtilen destek sayfasından kaynak.

Unix / Linux tabanlı sistemler için:

Sen kullanabilirsiniz opendir / readdir / closedir .

`` Ad '' girişi için bir dizinde arama yapan örnek kod:

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;

Yukarıdaki kılavuz sayfalarından kaynak kodu.

Windows tabanlı sistemler için:

Win32 API FindFirstFile / FindNextFile / FindClose işlevlerini kullanabilirsiniz.

Aşağıdaki C ++ örneği, FindFirstFile öğesinin minimal kullanımını gösterir.

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

Yukarıdaki msdn sayfalarından kaynak kodu.


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

7
C ++ 14 std::experimental::filesystemile, C ++ 17 ile std::filesystemboost ile benzer işlevselliğe sahip olan vardır (kütüphaneler boosttan türetilir). Shreevardhan'ın cevabını aşağıda görebilirsiniz.
Roi Danton


90

Bir işlev yeterlidir, herhangi bir üçüncü taraf kitaplığı kullanmanıza gerek yoktur (Windows için).

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

Not: @Sebastian tarafından belirtildiği gibi, değiştirmek olabilir *.*için *.extbu dizinde yalnızca EXT-dosyaları almak için (yani belirli bir türden) içinde.


20
Platforma özgü ise bu çözüm. Üçüncü taraf kütüphanelere ihtiyacınızın nedeni budur.
kraxor

9
@kraxor Evet, sadece Windows'da çalışıyor, ancak OP hiçbir zaman platformlar arası bir çözüm istemiyor. BTW, her zaman 3. kütüphaneleri kullanmadan bir şey seçmeyi tercih ederim (mümkünse).
herohuyongtao

7
@herohuyongtao OP hiçbir zaman bir platform belirlemedi ve genel bir soruya ağır bir platforma bağımlı çözüm vermek yanıltıcı olabilir. (Sadece PlayStation 3'te çalışan tek satırlık bir çözüm varsa? Bu iyi bir cevap mı?) Yanıtınızı yalnızca Windows üzerinde çalıştığını belirtmek için düzenlediğinizi görüyorum, sanırım bu iyi.
kraxor

1
@herohuyongtao OP ls ayrıştıramayacağını söyledi, muhtemelen unix üzerinde .. zaten Windows için iyi bir cevap.
Thomas

2
Bir std::vector<std::wstring>ve sonra fileName.c_str()dizeleri bir vektör yerine derleme olmaz kullanarak sona erdi .
PerryC

51

Yalnızca C çözümü için lütfen şuna bakın. Yalnızca fazladan bir başlık gerektirir:

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

Diğer seçeneklere göre bazı avantajlar:

  • Taşınabilir - POSIX yönünü ve Windows FindFirstFile dosyasını sarar
  • readdir_rMümkün olan yerlerde kullanır , yani (genellikle)
  • Aynı UNICODEmakrolar aracılığıyla Windows UTF-16'yı destekler
  • C90, bu yüzden çok eski derleyiciler bile kullanabilir

2
Çok güzel bir öneri. Henüz bir Windows bilgisayarında test etmedim ama OS X'de harika çalışıyor.
ArtOfWarfare

Kütüphane std :: string'i desteklemediğinden, tin.cir_open dosyasına file.c_str () iletemezsiniz. Bu durumda msvc 2015'te derleme sırasında C2664 hatası verir.
Stepan Yakovenko

33

globBu yeniden kullanılabilir sargı ile kullanmanızı tavsiye ederim . vector<string>Glob desenine uyan dosya yollarına karşılık gelen bir dosya oluşturur :

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

Hangi daha sonra gibi normal bir sistem joker desen ile çağrılabilir:

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

2
Glob () işlevinin sıfır döndürüp döndürmediğini test edin.
Camille Goudeseune

Tavsiye ettiğin gibi glob.h kullanmak istiyorum. Ama yine de .h dosyasını ekleyemiyorum: diyor No such file or directory. Lütfen bu sorunun nasıl çözüleceğini söyleyebilir misiniz?
Tofuw

Bu rutinin sadece bir seviye derine ineceğini unutmayın (özyineleme yok). Ayrıca, bir dosya veya dizin olup olmadığını belirlemek için hızlı bir denetim yapmaz; bu, geçiş GLOB_TILDEyaparak GLOB_TILDE | GLOB_MARKve ardından eğik çizgi ile biten yolları kontrol ederek kolayca yapabilirsiniz . İhtiyacınız olursa her iki modifikasyonda da değişiklik yapmanız gerekir.
Volomike

Bu çapraz platform uyumlu mu?
Nikhil Augustine

Maalesef üzerinden gizli bir şekilde gizli dosyalar bulamıyorsunuz glob.
LmTinyToon

23

Bir dizindeki dosya adlarını (klasör adları hariç) almak C++11için boost::filesystemkitaplığı kullanmanın çok basit bir kodu :

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

Çıktı şöyle:

file1.txt
file2.dat

Merhaba, bu kütüphaneyi nereden alabilirim?
Alexander Leon VI

2
@Alexander De Leon: Bu kütüphaneyi sites.org adresinden edinebilir , önce başlangıç ​​kılavuzunu okuyabilir, sonra boost::filesystemkütüphane boost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htm
Bad

23

Neden kullanmıyorsunuz 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;
}

Gerekli içeriği açıklarsanız bu daha iyi bir yanıt olabilir.
Volomike

2
Glob () 'un sıfır döndürdüğünü test edin!
orbitcowboy

Bu, * .txt
Kemin Zhou

20

Bence, snippet tüm dosyaları listelemek için kullanılabilir.

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

Yapı direncinin yapısı aşağıdadır

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

Bunu istiyorum.
selfboot

10

X-platform yöntemi için artırmayı deneyin

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

veya işletim sistemine özgü dosyalarınızı kullanın.


Bu bağlantı soruyu cevaplayabilse de, cevabın temel kısımlarını buraya eklemek ve bağlantıyı referans olarak sağlamak daha iyidir. Bağlantı verilen sayfa değişirse, yalnızca bağlantı yanıtları geçersiz olabilir. - Yorumdan
ice1000

@ ice1000 Cidden mi? Bu soru-cevap 2009
Tim

8

Win32 api kullanan bu sınıfa göz atın. Listeden foldernameistediğinizi sağlayarak bir örnek oluşturun, ardından dizinden bir getNextFilesonrakini almak için yöntemi çağırın filename. Bence ihtiyacı var windows.hve stdio.h.

class FileGetter{
    WIN32_FIND_DATAA found; 
    HANDLE hfind;
    char folderstar[255];       
    int chk;

public:
    FileGetter(char* folder){       
        sprintf(folderstar,"%s\\*.*",folder);
        hfind = FindFirstFileA(folderstar,&found);
        //skip .
        FindNextFileA(hfind,&found);        
    }

    int getNextFile(char* fname){
        //skips .. when called for the first time
        chk=FindNextFileA(hfind,&found);
        if (chk)
            strcpy(fname, found.cFileName);     
        return chk;
    }

};

6

GNU Manuel FTW

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

Ayrıca, bazen doğrudan kaynağa gitmek iyidir (pun amaçlı). Linux'taki en yaygın komutlardan bazılarının iç kısımlarına bakarak çok şey öğrenebilirsiniz. GNU'nun github üzerindeki çekirdeklerinin basit bir aynasını oluşturdum (okumak için).

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

Belki bu, Windows'a yönelik değildir, ancak bu yöntemler kullanılarak Unix varyantlarının kullanılmasıyla ilgili birkaç durum olabilir.

Umarım yardımcı olur...


5

Shreevardhan'ın cevabı harika çalışıyor. Ancak c ++ 14'te kullanmak istiyorsanız, sadece bir değişiklik yapınnamespace fs = experimental::filesystem;

yani

#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

Umarım bu kod size yardımcı olur.

#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_tyerel bir değişkenin adresini döndürür. Ayrıca, muhtemelen kendi yöntemlerinizi yazmak yerine WinAPI'de bulunan dönüştürme yöntemlerini kullanmalısınız.
Daniel Kamil Kozar

3

Bu uygulama, dizelerin bir dizisini belirtilen dizinin içeriğiyle dinamik olarak doldurarak amacınızı gerçekleştirir.

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

Buna nasıl diyebilirim? Bu işlevi ilk ifblokta çalıştırmaya çalıştığımda segfaults alıyorum . Şununla arıyorumchar **list; int numItems; exploreDirectory("/folder",list, numItems);
Hal T

2

Bu benim için çalışıyor. Kaynağı hatırlayamıyorsam özür dilerim. Muhtemelen bir man sayfasından.

#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 () öğesini kullanarak kök dizininizdeki tüm dosyaları doğrudan alabilirsiniz. Ardından, bu yol dosyalarının adını okuyun.

#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

Bu yanıt, Visual Studio ile çalışırken diğer yanıtların herhangi biriyle çalışırken sorun yaşayan Windows kullanıcıları için çalışmalıdır.

  1. Dirent.h dosyasını github sayfasından indirin. Ancak sadece Raw dirent.h dosyasını kullanmak ve aşağıdaki adımlarımı takip etmek daha iyidir (işte bu şekilde çalıştım).

    Dirent.h için Windows Github sayfası : dirent.h için Github sayfası

    Ham Dizin Dosyası: Ham dirent.h Dosyası

  2. Projenize gidin ve Yeni bir Öğe Ekleyin ( Ctrl+ Shift+ A). Bir başlık dosyası (.h) ekleyin ve dirent.h olarak adlandırın.

  3. Raw dirent.h Dosya kodunu başlığınıza yapıştırın .

  4. Kodunuza "dirent.h" ifadesini ekleyin.

  5. Aşağıdaki void filefinder()yöntemi kodunuza yerleştirin ve mainişlevinizden çağırın veya işlevi nasıl kullanmak istediğinizi düzenleyin.

    #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

Sistem çağır!

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

Sonra sadece dosyayı okuyun.

EDIT: Bu cevap bir kesmek olarak kabul edilmelidir, ancak daha zarif çözümlere erişiminiz yoksa gerçekten işe yarar (platforma özgü bir şekilde de olsa).


7
'Ls' komutunu yürütmem ve sonuçları programımdan ayrıştırmama izin verilmiyor. Böyle bir şey gönderecek birinin olacağını biliyordum ...
yyny

1

Bir dizinin dosyaları ve alt dizinleri genellikle bir ağaç yapısında saklandığından, sezgisel bir yol, her birini yinelemeli olarak çaprazlamak için DFS algoritmasını kullanmaktır. Windows işletim sisteminde io.h dosyasındaki temel dosya işlevlerini kullanarak bir örnek. Bu işlevleri başka bir platformda değiştirebilirsiniz. İfade etmek istediğim şey, DFS'nin temel fikrinin bu sorunu mükemmel bir şekilde karşılamasıdır.

#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

Her iki cevapta verilen örneği takip etmeye çalıştım std::filesystem::directory_entryve <<operatörün aşırı yüklenmesine sahip olmamış gibi göründüğünü belirtmek faydalı olabilir . Bunun yerine std::cout << p << std::endl;derlemek ve çalıştırabilmek için aşağıdakileri kullanmak zorunda kaldım:

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

pkendi kendine geçmeye çalışmak, std::cout <<aşırı yükleme hatasıyla sonuçlandı.


1

Hangi herohuyongtao'nun yayınladığı ve birkaç diğer gönderinin üzerine inşa:

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

FindFirstFile'ın beklenen girdi türü nedir?

Wstring dizgeye nasıl dönüştürülür?

Bu bir Windows çözümüdür.

Ben std :: string geçmek ve dizeleri bir vektör dönmek istedim beri ben birkaç dönüşüm yapmak zorunda kaldı.

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

Sadece kullanabileceğiniz multibyte kullanacağınızı biliyorsanız WIN32_FIND_DATAA, FindFirstFileAve FindNextFileA. Sonra sonucu multibyte veya Input unicode dönüştürmek gerekmeyecek.
Kiran Thilak

0

Sadece paylaşmak istediğim bir şey ve okuma materyali için teşekkür ederim. Biraz anlamak için fonksiyon ile oynayın. Hoşuna gidebilir. e uzatma için durdu, p yol için ve s yol ayırıcı için.

Yol, ayırıcıyı sonlandırmadan geçirilirse, yola bir ayırıcı eklenir. Uzantı için boş bir dize girilirse, işlev adında uzantısı olmayan herhangi bir dosyayı döndürür. Tek bir yıldız girildiyse, dizindeki tüm dosyalar döndürülür. E uzunluğu 0'dan büyükse, ancak tek bir * değilse, e sıfır konumunda bir nokta içermiyorsa bir nokta e'nin başına eklenir.

Dönen bir değer için. Sıfır uzunluklu bir harita döndürülürse, dizin bulunamadı ama hiçbir şey bulunamadı. 999 dizini dönüş değerinden elde edilebilir, ancak harita boyutu yalnızca 1 ise, dizin yolunun açılmasıyla ilgili bir sorun olduğu anlamına gelir.

Verimlilik için bu işlevin 3 küçük işleve ayrılabileceğini unutmayın. Bunun da ötesinde, girdiye bağlı olarak hangi işlevi arayacağını algılayacak bir arayan işlevi oluşturabilirsiniz. Bu neden daha verimli? Bir dosya olan her şeyi yakalayacaksanız, bu yöntemi tüm dosyaları kapmak için oluşturulan alt işlevi yapmak, sadece dosya olan her şeyi yakalayacak ve bir dosya bulduğunda başka bir gereksiz koşulu değerlendirmek zorunda kalmayacağını söyledi.

Bu, uzantısı olmayan dosyaları yakaladığınızda da geçerlidir. Bu amaçla oluşturulmuş belirli bir işlev, yalnızca bulunan nesnenin bir dosya olması ve ardından dosya adının içinde bir nokta olup olmadığına ilişkin hava durumunu değerlendirir.

Yalnızca çok fazla dosyaya sahip olmayan dizinleri okursanız kaydetme çok fazla olmayabilir. Ancak, büyük miktarda dizin okuyorsanız veya dizinde birkaç yüz binlerce dosya varsa, büyük bir tasarruf olabilir.

#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

Bu benim için çalıştı. Tüm dosyaların adlarını (yolsuz) içeren bir dosya yazar. Sonra o txt dosyasını okur ve sizin için yazdırır.

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

    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.