ฉันจะรับรายการไฟล์ในไดเรกทอรีโดยใช้ C หรือ C ++ ได้อย่างไร


593

ฉันจะกำหนดรายการไฟล์ในไดเรกทอรีจากภายในรหัส C หรือ C ++ ได้อย่างไร

ฉันไม่ได้รับอนุญาตให้ดำเนินการlsคำสั่งและแยกผลลัพธ์จากภายในโปรแกรมของฉัน


7
นี้เป็นซ้ำ609,236
chrish

1
ดูเพิ่มเติมstat()ข้อผิดพลาด readdir()'ไม่มีไฟล์หรือไดเรกทอรีดังกล่าวเมื่อชื่อไฟล์จะถูกส่งกลับโดย
Jonathan Leffler

1
@chrish - ใช่ แต่อันนี้มีคลาสสิก "ฉันไม่ได้รับอนุญาตให้ดำเนินการ 'ls'"! มันตรงว่าฉันจะรู้สึกปีที่ 1 วิชาวิทยาการคอมพิวเตอร์ ; D <3 x
James Bedford

1
C และ C ++ ไม่ใช่ภาษาเดียวกัน ดังนั้นขั้นตอนในการบรรลุภารกิจนี้จะแตกต่างกันในทั้งสองภาษา โปรดเลือกหนึ่งรายการและติดแท็กใหม่ตามนั้น
MD XF

2
และไม่มีภาษาเหล่านั้น (นอกเหนือจาก C ++ ตั้งแต่ C ++ 17) แม้จะมีแนวคิดของไดเรกทอรี - ดังนั้นคำตอบใด ๆ ที่น่าจะขึ้นอยู่กับระบบปฏิบัติการของคุณหรือในห้องสมุดนามธรรมที่คุณอาจใช้
Toby Speight

คำตอบ:


809

ในงานขนาดเล็กและเรียบง่ายที่ฉันไม่ได้ใช้บูสต์ฉันใช้dirent.hซึ่งใช้ได้กับ windows ด้วย:

DIR *dir;
struct dirent *ent;
if ((dir = opendir ("c:\\src\\")) != NULL) {
  /* print all the files and directories within directory */
  while ((ent = readdir (dir)) != NULL) {
    printf ("%s\n", ent->d_name);
  }
  closedir (dir);
} else {
  /* could not open directory */
  perror ("");
  return EXIT_FAILURE;
}

มันเป็นไฟล์ส่วนหัวขนาดเล็กและทำสิ่งที่ง่ายที่สุดที่คุณต้องการโดยไม่ต้องใช้วิธีการที่ใช้เทมเพลตขนาดใหญ่เช่นการเพิ่ม (ไม่มีความผิดฉันชอบการเพิ่ม!)

ผู้เขียนเลเยอร์ความเข้ากันได้ของ windows คือ Toni Ronkko ใน Unix เป็นส่วนหัวมาตรฐาน

อัพเดท 2017 :

ใน C ++ 17 std::filesystemตอนนี้จะมีวิธีการอย่างเป็นทางการไปยังแฟ้มรายชื่อของระบบไฟล์ของคุณ: มีคำตอบที่ยอดเยี่ยมจากShreevardhanด้านล่างด้วยรหัสแหล่งที่มานี้:

#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    std::string path = "/path/to/directory";
    for (const auto & entry : fs::directory_iterator(path))
        std::cout << entry.path() << std::endl;
}

5
@ArtOfWarfare: tinydir ไม่ได้สร้างขึ้นเมื่อตอบคำถามนี้ นอกจากนี้ยังเป็น wrapper รอบ dirent (POSIX) และ FindFirstFile (Windows) ในขณะที่ dirent.h เพียงล้อมรอบ dirent สำหรับ windows ฉันคิดว่ามันเป็นรสนิยมส่วนตัว แต่ dirent.h รู้สึกเป็นมาตรฐานมากขึ้น
ปีเตอร์ปาร์คเกอร์

7
@JoshC: เพราะ * ent เป็นเพียงตัวชี้กลับของการเป็นตัวแทนภายใน โดยการปิดไดเรกทอรีคุณจะกำจัด * ent เช่นกัน ฉันคิดว่ามันเป็นเพราะการออกแบบ * ent
ปีเตอร์ปาร์คเกอร์

42
ผู้คนรับจริง !! นี่เป็นคำถามตั้งแต่ปี 2009 และยังไม่ได้พูดถึง VS ดังนั้นอย่าวิพากษ์วิจารณ์ว่า IDE เต็มของคุณ (แม้ว่าค่อนข้างดี) IDE ไม่รองรับมาตรฐานระบบปฏิบัติการเก่ามาหลายศตวรรษ คำตอบของฉันยังบอกว่ามันเป็น "ว่าง" สำหรับ windows ไม่ใช่ "รวม" ใน IDE ใด ๆ จากนี้และตลอดเวลา ... ฉันค่อนข้างแน่ใจว่าคุณสามารถดาวน์โหลด dirent และใส่ไว้ในบางส่วนรวมถึง dir และ voila ที่นั่น
ปีเตอร์ปาร์คเกอร์

6
คำตอบนั้นทำให้เข้าใจผิด มันควรเริ่มต้นด้วย " ... ผมใช้dirent.hซึ่งเปิดแหล่งที่มาชั้นความเข้ากันได้ของ Windows ยังมีอยู่ "
rustyx

10
ด้วย C ++ 14 มีstd::experimental::filesystemด้วยภาษา C ++ 17 std::filesystemมี ดูคำตอบของ Shreevardhan ด้านล่าง ดังนั้นไม่จำเป็นต้องใช้ห้องสมุดบุคคลที่สาม
Roi Danton

347

C ++ 17 ตอนนี้มี a std::filesystem::directory_iteratorซึ่งสามารถใช้เป็น

#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main() {
    std::string path = "/path/to/directory";
    for (const auto & entry : fs::directory_iterator(path))
        std::cout << entry.path() << std::endl;
}

นอกจากนี้ยังstd::filesystem::recursive_directory_iteratorสามารถทำซ้ำไดเรกทอรีย่อยได้เช่นกัน


28
AFAIK ยังสามารถนำมาใช้ใน C ++ 14 namespace fs = std::experimental::filesystem;แต่มีก็ยังคงทดลอง: มันดูเหมือนว่าจะโอเค
PeterK

7
นี่ควรเป็นคำตอบที่ต้องการสำหรับการใช้งานปัจจุบัน (เริ่มต้นด้วย C ++ 17)
green diod

4
เอาใจใส่เมื่อผ่านstd::filesystem::pathไปstd::coutเครื่องหมายคำพูดจะรวมอยู่ในผลลัพธ์ เพื่อหลีกเลี่ยงปัญหานั้นให้ผนวก.string()เส้นทางเพื่อทำการแปลงอย่างชัดเจนแทนการแปลงโดยนัย (ที่นี่std::cout << p.string() << std::endl;) ตัวอย่าง: coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3
Roi Danton

2
แล้วอักขระที่ไม่ใช่ ASCII ในชื่อไฟล์ล่ะ ไม่ควรstd::wstringใช้หรือเป็นชนิดจากตัววนซ้ำ
anddero

2
ผมไม่แน่ใจว่าถ้าฉันคนเดียวในเรื่องนี้ แต่ไม่มีการเชื่อมโยงกับผมได้รับ-lstdc++fs SIGSEGV (Address boundary error)ฉันไม่พบที่ใดก็ได้ในเอกสารที่จำเป็นต้องใช้และตัวเชื่อมโยงก็ไม่ได้ให้เงื่อนงำใด ๆ นี้ทำงานให้กับทั้งสองและg++ 8.3.0 clang 8.0.0-3ใครบ้างมีความเข้าใจอย่างถ่องแท้ว่าสิ่งใดที่ระบุไว้ในเอกสาร / รายละเอียด?
swalog

229

น่าเสียดายที่มาตรฐาน C ++ ไม่ได้กำหนดวิธีการมาตรฐานในการทำงานกับไฟล์และโฟลเดอร์ด้วยวิธีนี้

เนื่องจากไม่มีทางข้ามแพลตฟอร์มวิธีข้ามแพลตฟอร์มที่ดีที่สุดคือการใช้ห้องสมุดเช่นโมดูลเพิ่มระบบแฟ้ม

วิธีการเพิ่มข้ามแพลตฟอร์ม:

ฟังก์ชั่นต่อไปนี้ให้เส้นทางไดเรกทอรีและชื่อไฟล์ค้นหาไดเรกทอรีและไดเรกทอรีย่อยซ้ำเพื่อค้นหาชื่อไฟล์กลับบูลและหากประสบความสำเร็จเส้นทางไปยังไฟล์ที่พบ

bool find_file(const path & dir_path,         // in this directory,
               const std::string & file_name, // search for this name,
               path & path_found)             // placing path here if found
{
    if (!exists(dir_path)) 
        return false;

    directory_iterator end_itr; // default construction yields past-the-end

    for (directory_iterator itr(dir_path); itr != end_itr; ++itr)
    {
        if (is_directory(itr->status()))
        {
            if (find_file(itr->path(), file_name, path_found)) 
                return true;
        }
        else if (itr->leaf() == file_name) // see below
        {
            path_found = itr->path();
            return true;
        }
    }
    return false;
}

แหล่งที่มาจากหน้าเพิ่มที่กล่าวถึงข้างต้น

สำหรับระบบที่ใช้ Unix / Linux:

คุณสามารถใช้opendir / readdir / closedir

โค้ดตัวอย่างที่ค้นหาไดเรกทอรีสำหรับรายการ `` ชื่อ '' คือ:

len = strlen(name);
dirp = opendir(".");
while ((dp = readdir(dirp)) != NULL)
        if (dp->d_namlen == len && !strcmp(dp->d_name, name)) {
                (void)closedir(dirp);
                return FOUND;
        }
(void)closedir(dirp);
return NOT_FOUND;

ซอร์สโค้ดจาก man page ด้านบน

สำหรับระบบที่ใช้ windows:

คุณสามารถใช้ Win32 API FindFirstFile / FindNextFile / FindCloseฟังก์ชั่น

ตัวอย่าง C ++ ต่อไปนี้แสดงการใช้ FindFirstFile ให้น้อยที่สุด

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

void _tmain(int argc, TCHAR *argv[])
{
   WIN32_FIND_DATA FindFileData;
   HANDLE hFind;

   if( argc != 2 )
   {
      _tprintf(TEXT("Usage: %s [target_file]\n"), argv[0]);
      return;
   }

   _tprintf (TEXT("Target file is %s\n"), argv[1]);
   hFind = FindFirstFile(argv[1], &FindFileData);
   if (hFind == INVALID_HANDLE_VALUE) 
   {
      printf ("FindFirstFile failed (%d)\n", GetLastError());
      return;
   } 
   else 
   {
      _tprintf (TEXT("The first file found is %s\n"), 
                FindFileData.cFileName);
      FindClose(hFind);
   }
}

ซอร์สโค้ดจากหน้า msdn ด้านบน


การใช้งาน:FindFirstFile(TEXT("D:\\IMAGE\\MYDIRECTORY\\*"), &findFileData);
КонстантинВан

7
ด้วย C ++ 14 นั่นคือstd::experimental::filesystemด้วย C ++ 17 นั่นคือstd::filesystemซึ่งมีฟังก์ชั่นที่คล้ายกันเช่นการเพิ่ม (libs ที่ได้มาจากการเพิ่ม) ดูคำตอบของ Shreevardhan ด้านล่าง
ร้อย Danton

สำหรับ windows อ้างถึงdocs.microsoft.com/en-us/windows/desktop/FileIO/ …สำหรับรายละเอียด
FindOutIslamNow

90

ฟังก์ชั่นเดียวก็เพียงพอแล้วคุณไม่จำเป็นต้องใช้ห้องสมุดบุคคลที่สาม (สำหรับ Windows)

#include <Windows.h>

vector<string> get_all_files_names_within_folder(string folder)
{
    vector<string> names;
    string search_path = folder + "/*.*";
    WIN32_FIND_DATA fd; 
    HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd); 
    if(hFind != INVALID_HANDLE_VALUE) { 
        do { 
            // read all (real) files in current folder
            // , delete '!' read other 2 default folder . and ..
            if(! (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
                names.push_back(fd.cFileName);
            }
        }while(::FindNextFile(hFind, &fd)); 
        ::FindClose(hFind); 
    } 
    return names;
}

PS: ตามที่กล่าวถึงโดย @Sebastian คุณสามารถเปลี่ยน*.*เป็น*.extเพื่อรับเฉพาะไฟล์ EXT (เช่นประเภทที่ระบุ) ในไดเรกทอรีนั้น


20
วิธีนี้ถ้าเฉพาะแพลตฟอร์ม นั่นคือเหตุผลที่คุณต้องการห้องสมุดบุคคลที่สาม
kraxor

9
@ kraxor ใช่มันใช้งานได้เฉพาะใน Windows แต่ OP ไม่เคยขอให้มีวิธีการข้ามแพลตฟอร์ม BTW ฉันมักจะเลือกบางสิ่งบางอย่างโดยไม่ใช้ห้องสมุดที่ 3 (ถ้าเป็นไปได้)
herohuyongtao

7
@herohuyongtao OP ไม่เคยระบุแพลตฟอร์มและการแก้ปัญหาที่ขึ้นอยู่กับแพลตฟอร์มอย่างมากสำหรับคำถามทั่วไปอาจทำให้เข้าใจผิด (จะเกิดอะไรขึ้นถ้ามีวิธีแก้ปัญหาแบบบรรทัดเดียวที่ใช้งานได้กับ PlayStation 3 เท่านั้นคำตอบที่ดีคือที่นี่ใช่ไหม) ฉันเห็นคุณแก้ไขคำตอบของคุณเพื่อระบุว่ามันใช้งานได้กับ Windows เท่านั้นฉันคิดว่ามันใช้ได้ดี
kraxor

1
@herohuyongtao OP พูดถึงว่าเขาแยกวิเคราะห์ ls ไม่ได้หมายความว่าเขาน่าจะอยู่บนยูนิกซ์ .. อยู่ดีคำตอบที่ดีสำหรับ Windows
โทมัส

2
ฉันลงเอยด้วยการใช้ a std::vector<std::wstring>แล้วfileName.c_str()แทนเวกเตอร์ของสตริงซึ่งจะไม่คอมไพล์
PerryC

51

สำหรับวิธีการแก้ปัญหา C เท่านั้นโปรดตรวจสอบนี้ ต้องการเพียงส่วนหัวเพิ่มเติมเท่านั้น:

https://github.com/cxong/tinydir

tinydir_dir dir;
tinydir_open(&dir, "/path/to/dir");

while (dir.has_next)
{
    tinydir_file file;
    tinydir_readfile(&dir, &file);

    printf("%s", file.name);
    if (file.is_dir)
    {
        printf("/");
    }
    printf("\n");

    tinydir_next(&dir);
}

tinydir_close(&dir);

ข้อดีกว่าตัวเลือกอื่น ๆ :

  • มันเป็นแบบพกพา - ล้อมรอบ POSIX และ Windows FindFirstFile
  • มันใช้ในreaddir_rกรณีที่มีให้ซึ่งหมายความว่าเป็น threadsafe (ปกติ)
  • รองรับ Windows UTF-16 ผ่านUNICODEมาโครตัวเดียวกัน
  • มันคือ C90 ดังนั้นแม้แต่คอมไพเลอร์โบราณก็สามารถใช้มันได้

2
คำแนะนำที่ดีมาก ฉันยังไม่ได้ทดสอบกับคอมพิวเตอร์ที่ใช้ windows แต่มันใช้งานได้ดีบน OS X
ArtOfWarfare

ไลบรารีไม่รองรับ std :: string ดังนั้นคุณจึงไม่สามารถส่ง file.c_str () ไปที่ tinydir_open มันให้ข้อผิดพลาด C2664 ในระหว่างการรวบรวมใน msvc 2015 ในกรณีนี้
Stepan Yakovenko

33

ฉันแนะนำให้ใช้globกับ wrapper ที่ใช้ซ้ำได้นี้ มันสร้างที่vector<string>สอดคล้องกับเส้นทางของไฟล์ที่เหมาะสมกับรูปแบบ glob:

#include <glob.h>
#include <vector>
using std::vector;

vector<string> globVector(const string& pattern){
    glob_t glob_result;
    glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
    vector<string> files;
    for(unsigned int i=0;i<glob_result.gl_pathc;++i){
        files.push_back(string(glob_result.gl_pathv[i]));
    }
    globfree(&glob_result);
    return files;
}

ซึ่งสามารถเรียกด้วยรูปแบบสัญลักษณ์แทนระบบปกติเช่น:

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

2
ทดสอบว่า glob () ส่งคืนค่าศูนย์
Camille Goudeseune

ฉันต้องการใช้ glob.h ตามที่คุณแนะนำ แต่ยังคงฉันไม่สามารถรวมแฟ้ม .h: No such file or directoryมันบอกว่า คุณช่วยบอกฉันได้ไหมว่าจะแก้ปัญหานี้ได้อย่างไร?
Tofuw

โปรดทราบว่ารูทีนนี้มีความลึกเพียงระดับเดียวเท่านั้น (ไม่มีการเรียกซ้ำ) นอกจากนี้ยังไม่ทำการตรวจสอบอย่างรวดเร็วเพื่อตรวจสอบว่าเป็นไฟล์หรือไดเรกทอรีซึ่งคุณสามารถทำได้อย่างง่ายดายโดยสลับGLOB_TILDEกับGLOB_TILDE | GLOB_MARKแล้วตรวจสอบเส้นทางที่ลงท้ายด้วยเครื่องหมายทับ คุณจะต้องทำการแก้ไขหากคุณต้องการ
Volomike

ใช้งานข้ามแพลตฟอร์มได้หรือไม่
Nikhil Augustine

globแต่น่าเสียดายที่คุณไม่สามารถหาไฟล์ที่ซ่อนอยู่อย่างสม่ำเสมอผ่าน
LmTinyToon

23

นี่คือรหัสง่ายๆในการC++11ใช้boost::filesystemไลบรารีเพื่อรับชื่อไฟล์ในไดเรกทอรี (ยกเว้นชื่อโฟลเดอร์):

#include <string>
#include <iostream>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;

int main()
{
    path p("D:/AnyFolder");
    for (auto i = directory_iterator(p); i != directory_iterator(); i++)
    {
        if (!is_directory(i->path())) //we eliminate directories
        {
            cout << i->path().filename().string() << endl;
        }
        else
            continue;
    }
}

ผลผลิตเป็นเช่น:

file1.txt
file2.dat

สวัสดีและฉันจะหาห้องสมุดนี้ได้ที่ไหน
Alexander Leon VI

2
@Alexander De Leon: คุณสามารถรับห้องสมุดนี้ได้ที่เว็บไซต์boost.orgของพวกเขาอ่านคู่มือการเริ่มต้นใช้งานก่อนจากนั้นใช้boost::filesystemห้องสมุดของพวกเขาboost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htm
Bad

23

ทำไมไม่ใช้glob()?

#include <glob.h>

glob_t glob_result;
glob("/your_directory/*",GLOB_TILDE,NULL,&glob_result);
for(unsigned int i=0; i<glob_result.gl_pathc; ++i){
  cout << glob_result.gl_pathv[i] << endl;
}

นี่อาจเป็นคำตอบที่ดีกว่าถ้าคุณอธิบายถึงสิ่งที่จำเป็นต้องมี
Volomike

2
ทดสอบว่า glob () ส่งคืนค่าศูนย์!
orbitcowboy

นี่เป็นสิ่งที่ดีเมื่อคุณรู้ว่าไฟล์ที่คุณกำลังมองหาเช่น * .txt
Kemin Zhou

20

ฉันคิดว่าตัวอย่างด้านล่างสามารถใช้เพื่อแสดงรายการไฟล์ทั้งหมด

#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>

static void list_dir(const char *path)
{
    struct dirent *entry;
    DIR *dir = opendir(path);
    if (dir == NULL) {
        return;
    }

    while ((entry = readdir(dir)) != NULL) {
        printf("%s\n",entry->d_name);
    }

    closedir(dir);
}

ต่อไปนี้เป็นโครงสร้างของ struct dirent

struct dirent {
    ino_t d_ino; /* inode number */
    off_t d_off; /* offset to the next dirent */
    unsigned short d_reclen; /* length of this record */
    unsigned char d_type; /* type of file */
    char d_name[256]; /* filename */
};

ฉันต้องการอันนี้
เริ่มต้นด้วยตนเอง

10

ลองเพิ่มประสิทธิภาพสำหรับวิธีการ x-platform

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

หรือเพียงแค่ใช้ไฟล์เฉพาะระบบปฏิบัติการของคุณ


แม้ว่าลิงก์นี้อาจตอบคำถามได้ดีกว่าหากรวมส่วนสำคัญของคำตอบไว้ที่นี่และให้ลิงก์สำหรับการอ้างอิง คำตอบสำหรับลิงก์เท่านั้นอาจไม่ถูกต้องหากหน้าเว็บที่เชื่อมโยงมีการเปลี่ยนแปลง - จากการรีวิว
ice1000

@ ice1000 อย่างจริงจัง? คำถาม & คำตอบนี้เริ่มตั้งแต่ปี 2009
Tim

8

ลองดูคลาสนี้ที่ใช้ win32 api เพียงสร้างอินสแตนซ์โดยระบุสิ่งfoldernameที่คุณต้องการให้รายชื่อจากนั้นเรียกใช้getNextFileเมธอดเพื่อรับสิ่งต่อไปfilenameจากไดเรกทอรี ฉันคิดว่ามันตอบสนองความต้องการและwindows.hstdio.h

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

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

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

};

6

คู่มือ GNU FTW

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

นอกจากนี้บางครั้งก็เป็นการดีที่จะไปยังแหล่งข้อมูล (ตั้งใจให้เล่น) คุณสามารถเรียนรู้ได้มากมายโดยดูที่คำสั่งที่พบบ่อยที่สุดใน Linux ฉันได้ตั้งค่ากระจกเรียบง่ายของ coreutils ของ GNU บน github (สำหรับการอ่าน)

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

บางทีนี่อาจไม่ได้อยู่ที่ Windows แต่มีหลายกรณีที่ใช้ Unix Variants โดยใช้วิธีการเหล่านี้

หวังว่าจะช่วย ...


5

คำตอบของ Shreevardhan ใช้งานได้ดี แต่ถ้าคุณต้องการใช้ใน c ++ 14 เพียงแค่ทำการเปลี่ยนแปลงnamespace fs = experimental::filesystem;

กล่าวคือ

#include <string>
#include <iostream>
#include <filesystem>

using namespace std;
namespace fs = experimental::filesystem;

int main()
{
    string path = "C:\\splits\\";
    for (auto & p : fs::directory_iterator(path))
        cout << p << endl;
    int n;
    cin >> n;
}

4
char **getKeys(char *data_dir, char* tablename, int *num_keys)
{
    char** arr = malloc(MAX_RECORDS_PER_TABLE*sizeof(char*));
int i = 0;
for (;i < MAX_RECORDS_PER_TABLE; i++)
    arr[i] = malloc( (MAX_KEY_LEN+1) * sizeof(char) );  


char *buf = (char *)malloc( (MAX_KEY_LEN+1)*sizeof(char) );
snprintf(buf, MAX_KEY_LEN+1, "%s/%s", data_dir, tablename);

DIR* tableDir = opendir(buf);
struct dirent* getInfo;

readdir(tableDir); // ignore '.'
readdir(tableDir); // ignore '..'

i = 0;
while(1)
{


    getInfo = readdir(tableDir);
    if (getInfo == 0)
        break;
    strcpy(arr[i++], getInfo->d_name);
}
*(num_keys) = i;
return arr;
}

3

ฉันหวังว่ารหัสนี้จะช่วยคุณ

#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;

string wchar_t2string(const wchar_t *wchar)
{
    string str = "";
    int index = 0;
    while(wchar[index] != 0)
    {
        str += (char)wchar[index];
        ++index;
    }
    return str;
}

wchar_t *string2wchar_t(const string &str)
{
    wchar_t wchar[260];
    int index = 0;
    while(index < str.size())
    {
        wchar[index] = (wchar_t)str[index];
        ++index;
    }
    wchar[index] = 0;
    return wchar;
}

vector<string> listFilesInDirectory(string directoryName)
{
    WIN32_FIND_DATA FindFileData;
    wchar_t * FileName = string2wchar_t(directoryName);
    HANDLE hFind = FindFirstFile(FileName, &FindFileData);

    vector<string> listFileNames;
    listFileNames.push_back(wchar_t2string(FindFileData.cFileName));

    while (FindNextFile(hFind, &FindFileData))
        listFileNames.push_back(wchar_t2string(FindFileData.cFileName));

    return listFileNames;
}

void main()
{
    vector<string> listFiles;
    listFiles = listFilesInDirectory("C:\\*.txt");
    for each (string str in listFiles)
        cout << str << endl;
}

4
-1 string2wchar_tส่งคืนที่อยู่ของตัวแปรท้องถิ่น นอกจากนี้คุณควรใช้วิธีการแปลงที่มีอยู่ใน WinAPI แทนที่จะเขียนวิธีของคุณเอง
Daniel Kamil Kozar

3

การใช้งานนี้ตระหนักถึงวัตถุประสงค์ของคุณเติมอาร์เรย์ของสตริงแบบไดนามิกด้วยเนื้อหาของไดเรกทอรีที่ระบุ

int exploreDirectory(const char *dirpath, char ***list, int *numItems) {
    struct dirent **direntList;
    int i;
    errno = 0;

    if ((*numItems = scandir(dirpath, &direntList, NULL, alphasort)) == -1)
        return errno;

    if (!((*list) = malloc(sizeof(char *) * (*numItems)))) {
        fprintf(stderr, "Error in list allocation for file list: dirpath=%s.\n", dirpath);
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < *numItems; i++) {
        (*list)[i] = stringDuplication(direntList[i]->d_name);
    }

    for (i = 0; i < *numItems; i++) {
        free(direntList[i]);
    }

    free(direntList);

    return 0;
}

ฉันจะเรียกสิ่งนี้ได้อย่างไร ฉันได้รับ segfaults เมื่อฉันพยายามเรียกใช้ฟังก์ชันนี้ในifบล็อกแรก ฉันกำลังโทรหาด้วยchar **list; int numItems; exploreDirectory("/folder",list, numItems);
Hal T

2

มันใช้งานได้สำหรับฉัน ฉันขอโทษถ้าฉันจำแหล่งที่ไม่ได้ มันอาจมาจากหน้าคน

#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 :: experiment :: filesystem :: directory_iterator () จากนั้นอ่านชื่อของไฟล์พา ธ เหล่านี้

#include <iostream>
#include <filesystem>
#include <string>
#include <direct.h>
using namespace std;
namespace fs = std::experimental::filesystem;
void ShowListFile(string path)
{
for(auto &p: fs::directory_iterator(path))  /*get directory */
     cout<<p.path().filename()<<endl;   // get file name
}

int main() {

ShowListFile("C:/Users/dell/Pictures/Camera Roll/");
getchar();
return 0;
}

2

คำตอบนี้ควรใช้ได้กับผู้ใช้ Windows ที่มีปัญหาในการทำงานกับ Visual Studio ด้วยคำตอบอื่น ๆ

  1. ดาวน์โหลดไฟล์ dirent.h จากหน้า github แต่ดีกว่าที่จะใช้ไฟล์ Raw dirent.h และทำตามขั้นตอนของฉันด้านล่าง (เป็นวิธีที่ทำให้ฉันใช้งานได้)

    หน้า Github สำหรับ dirent.h สำหรับ Windows: หน้า Github สำหรับ dirent.h

    ไฟล์Raw Dirent : ไฟล์Raw dirent.h

  2. ไปที่โครงการของคุณและเพิ่มรายการใหม่ ( Ctrl+ Shift+ A) เพิ่มไฟล์ส่วนหัว (.h) และตั้งชื่อ dirent.h

  3. วางรหัสไฟล์ดิบ dirent.hลงในส่วนหัวของคุณ

  4. รวม "dirent.h" ในรหัสของคุณ

  5. ใส่void filefinder()วิธีการด้านล่างในรหัสของคุณและเรียกมันจากmainฟังก์ชั่นของคุณหรือแก้ไขฟังก์ชั่นวิธีที่คุณต้องการใช้

    #include <stdio.h>
    #include <string.h>
    #include "dirent.h"
    
    string path = "C:/folder"; //Put a valid path here for folder
    
    void filefinder()
    {
        DIR *directory = opendir(path.c_str());
        struct dirent *direntStruct;
    
        if (directory != NULL) {
            while (direntStruct = readdir(directory)) {
                printf("File Name: %s\n", direntStruct->d_name); //If you are using <stdio.h>
                //std::cout << direntStruct->d_name << std::endl; //If you are using <iostream>
            }
        }
        closedir(directory);
    }

1

ระบบเรียกมันว่า!

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

จากนั้นเพียงแค่อ่านไฟล์

แก้ไข: คำตอบนี้ควรพิจารณาว่าเป็นการแฮ็ก แต่มันใช้งานได้จริง (แม้ว่าจะเป็นวิธีเฉพาะของแพลตฟอร์ม) หากคุณไม่สามารถเข้าถึงโซลูชันที่หรูหรากว่านี้ได้


7
ฉันไม่ได้รับอนุญาตให้ดำเนินการคำสั่ง 'ls' และแยกผลลัพธ์จากภายในโปรแกรมของฉัน ฉันรู้ว่าจะมีใครบางคนที่จะส่งบางสิ่งเช่นนี้ ...
yyny

1

เนื่องจากไฟล์และไดเรกทอรีย่อยของไดเรกทอรีโดยทั่วไปจะถูกเก็บไว้ในโครงสร้างแบบต้นไม้วิธีที่ง่ายคือการใช้อัลกอริทึม DFS เพื่อวนซ้ำแต่ละไฟล์ นี่คือตัวอย่างในระบบปฏิบัติการ windows โดยใช้ฟังก์ชันไฟล์พื้นฐานใน io.h คุณสามารถแทนที่ฟังก์ชั่นเหล่านี้ในแพลตฟอร์มอื่น สิ่งที่ฉันต้องการแสดงคือความคิดพื้นฐานของ DFS ตรงกับปัญหานี้อย่างสมบูรณ์

#include<io.h>
#include<iostream.h>
#include<string>
using namespace std;

void TraverseFilesUsingDFS(const string& folder_path){
   _finddata_t file_info;
   string any_file_pattern = folder_path + "\\*";
   intptr_t handle = _findfirst(any_file_pattern.c_str(),&file_info);
   //If folder_path exsist, using any_file_pattern will find at least two files "." and "..", 
   //of which "." means current dir and ".." means parent dir
   if (handle == -1){
       cerr << "folder path not exist: " << folder_path << endl;
       exit(-1);
   }
   //iteratively check each file or sub_directory in current folder
   do{
       string file_name=file_info.name; //from char array to string
       //check whtether it is a sub direcotry or a file
       if (file_info.attrib & _A_SUBDIR){
            if (file_name != "." && file_name != ".."){
               string sub_folder_path = folder_path + "\\" + file_name;                
               TraverseFilesUsingDFS(sub_folder_path);
               cout << "a sub_folder path: " << sub_folder_path << endl;
            }
       }
       else
            cout << "file name: " << file_name << endl;
    } while (_findnext(handle, &file_info) == 0);
    //
    _findclose(handle);
}

1

ผมพยายามที่จะทำตามตัวอย่างที่ให้ไว้ในทั้ง คำตอบและมันอาจจะเป็นที่น่าสังเกตว่ามันดูราวกับว่าstd::filesystem::directory_entryได้ถูกเปลี่ยนไปไม่ได้เกินของ<<ผู้ประกอบการ แทนที่จะstd::cout << p << std::endl;ต้องใช้สิ่งต่อไปนี้เพื่อรวบรวมและทำให้มันใช้งานได้:

#include <iostream>
#include <filesystem>
#include <string>
namespace fs = std::filesystem;

int main() {
    std::string path = "/path/to/directory";
    for(const auto& p : fs::directory_iterator(path))
        std::cout << p.path() << std::endl;
}

การพยายามส่งpด้วยตนเองเพื่อstd::cout <<ให้เกิดข้อผิดพลาดโอเวอร์โหลดที่ขาดหายไป


1

สร้างสิ่งที่ herohuyongtao โพสต์และโพสต์อื่น ๆ :

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

ประเภทการป้อนข้อมูลที่คาดหวังของ FindFirstFile คืออะไร

วิธีการแปลง wstring เป็นสตริง?

นี่คือโซลูชัน Windows

เนื่องจากฉันต้องการส่งผ่าน std :: string และส่งคืนเวกเตอร์ของสตริงฉันจึงต้องทำการแปลงสองสามครั้ง

#include <string>
#include <Windows.h>
#include <vector>
#include <locale>
#include <codecvt>

std::vector<std::string> listFilesInDir(std::string path)
{
    std::vector<std::string> names;
    //Convert string to wstring
    std::wstring search_path = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(path);
    WIN32_FIND_DATA fd;
    HANDLE hFind = FindFirstFile(search_path.c_str(), &fd);
    if (hFind != INVALID_HANDLE_VALUE) 
    {
        do 
        {
            // read all (real) files in current folder
            // , delete '!' read other 2 default folder . and ..
            if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 
            {
                //convert from wide char to narrow char array
                char ch[260];
                char DefChar = ' ';
                WideCharToMultiByte(CP_ACP, 0, fd.cFileName, -1, ch, 260, &DefChar, NULL);
                names.push_back(ch);
            }
        } 
        while (::FindNextFile(hFind, &fd));
        ::FindClose(hFind);
    }
    return names;
}

ถ้าคุณรู้ว่าคุณจะเป็นเพียงการใช้สัญลักษณ์คุณสามารถใช้ WIN32_FIND_DATAA, และFindFirstFileA FindNextFileAจากนั้นไม่จำเป็นต้องแปลงผลลัพธ์เป็นหลายไบต์หรือป้อนเป็น Unicode
Kiran Thilak

0

เป็นเพียงสิ่งที่ฉันต้องการแบ่งปันและขอขอบคุณสำหรับเนื้อหาการอ่าน ลองฟังด้วยฟังก์ชั่นสักหน่อยเพื่อทำความเข้าใจ คุณอาจจะชอบมัน e ย่อมาจากส่วนขยาย p เป็นเส้นทางและ s สำหรับตัวคั่นเส้นทาง

หากเส้นทางถูกส่งโดยไม่มีตัวคั่นสิ้นสุดตัวคั่นจะถูกผนวกเข้ากับเส้นทาง สำหรับส่วนขยายหากมีการป้อนสตริงว่างฟังก์ชันจะส่งคืนไฟล์ใด ๆ ที่ไม่มีนามสกุลในชื่อ หากใส่ดาวดวงเดียวมากกว่าไฟล์ทั้งหมดในไดเรกทอรีจะถูกส่งคืน หากความยาว e มากกว่า 0 แต่ไม่ใช่เพียงหนึ่งเดียว * จุดนั้นจะถูกเติมให้เป็น e หาก e ไม่มีจุดที่ตำแหน่งศูนย์

สำหรับค่าส่งคืน หากส่งคืนแผนที่ที่มีความยาวเป็นศูนย์จะไม่พบสิ่งใดนอกจากไดเรกทอรีนั้นเปิดอยู่ หากดัชนี 999 พร้อมใช้งานจากค่าส่งคืน แต่ขนาดของแผนที่เป็นเพียง 1 นั่นหมายความว่ามีปัญหากับการเปิดเส้นทางไดเรกทอรี

โปรดทราบว่าเพื่อประสิทธิภาพฟังก์ชั่นนี้สามารถแบ่งออกเป็น 3 ฟังก์ชั่นขนาดเล็ก ด้านบนของที่คุณสามารถสร้างฟังก์ชั่นการโทรที่จะตรวจสอบฟังก์ชั่นที่มันจะเรียกตามอินพุต ทำไมจึงมีประสิทธิภาพมากกว่า กล่าวว่าหากคุณกำลังจะคว้าทุกอย่างที่เป็นไฟล์การทำวิธีการนั้นเป็นฟังก์ชั่นย่อยที่สร้างขึ้นเพื่อคว้าไฟล์ทั้งหมดจะเพิ่งคว้าทุกสิ่งที่เป็นไฟล์และไม่จำเป็นต้องประเมินเงื่อนไขที่ไม่จำเป็นอื่น ๆ ทุกครั้งที่พบไฟล์

ซึ่งจะนำไปใช้เมื่อคุณคว้าไฟล์ที่ไม่มีส่วนขยาย ฟังก์ชั่นที่สร้างขึ้นเฉพาะสำหรับวัตถุประสงค์นั้นจะประเมินสภาพอากาศเฉพาะเมื่อวัตถุที่พบนั้นเป็นไฟล์และถ้าชื่อไฟล์นั้นมีจุดอยู่ในนั้นหรือไม่

การบันทึกอาจไม่มากถ้าคุณอ่านเฉพาะไดเรกทอรีที่มีไฟล์ไม่มาก แต่ถ้าคุณกำลังอ่านไดเรกทอรีจำนวนมากหรือถ้าไดเรกทอรีมีไฟล์สองแสนไฟล์มันอาจเป็นการประหยัดขนาดใหญ่

#include <stdio.h>
#include <sys/stat.h>
#include <iostream>
#include <dirent.h>
#include <map>

std::map<int, std::string> getFile(std::string p, std::string e = "", unsigned char s = '/'){
    if ( p.size() > 0 ){
        if (p.back() != s) p += s;
    }
    if ( e.size() > 0 ){
        if ( e.at(0) != '.' && !(e.size() == 1 && e.at(0) == '*') ) e = "." + e;
    }

    DIR *dir;
    struct dirent *ent;
    struct stat sb;
    std::map<int, std::string> r = {{999, "FAILED"}};
    std::string temp;
    int f = 0;
    bool fd;

    if ( (dir = opendir(p.c_str())) != NULL ){
        r.erase (999);
        while ((ent = readdir (dir)) != NULL){
            temp = ent->d_name;
            fd = temp.find(".") != std::string::npos? true : false;
            temp = p + temp;

            if (stat(temp.c_str(), &sb) == 0 && S_ISREG(sb.st_mode)){
                if ( e.size() == 1 && e.at(0) == '*' ){
                    r[f] = temp;
                    f++;
                } else {
                    if (e.size() == 0){
                        if ( fd == false ){
                            r[f] = temp;
                            f++;
                        }
                        continue;
                    }

                    if (e.size() > temp.size()) continue;

                    if ( temp.substr(temp.size() - e.size()) == e ){
                        r[f] = temp;
                        f++;
                    }
                }
            }
        }

        closedir(dir);
        return r;
    } else {
        return r;
    }
}

void printMap(auto &m){
    for (const auto &p : m) {
        std::cout << "m[" << p.first << "] = " << p.second << std::endl;
    }
}

int main(){
    std::map<int, std::string> k = getFile("./", "");
    printMap(k);
    return 0;
}

0
#include<iostream>
#include <dirent.h>
using namespace std;
char ROOT[]={'.'};

void listfiles(char* path){
    DIR * dirp = opendir(path);
    dirent * dp;
    while ( (dp = readdir(dirp)) !=NULL ) {
         cout << dp->d_name << " size " << dp->d_reclen<<std::endl;
    }
    (void)closedir(dirp);
}

int main(int argc, char **argv)
{
    char* path;
    if (argc>1) path=argv[1]; else path=ROOT;

    cout<<"list files in ["<<path<<"]"<<std::endl;
    listfiles(path);

    return 0;
}

-1

สิ่งนี้ใช้ได้สำหรับฉัน มันเขียนไฟล์ที่มีชื่อ (ไม่มีเส้นทาง) ของไฟล์ทั้งหมด จากนั้นจะอ่านไฟล์ txt นั้นและพิมพ์ให้คุณ

void DisplayFolderContent()
    {

        system("dir /n /b * > file_names.txt");
        char ch;
        std::fstream myStream("file_names.txt", std::fstream::in);
        while (myStream.get(ch))
        {
            std::cout << ch;
        }

    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.