คุณทำซ้ำทุกไฟล์ / ไดเร็กทอรีแบบวนซ้ำใน C ++ มาตรฐานได้อย่างไร


115

คุณทำซ้ำทุกไฟล์ / ไดเร็กทอรีแบบวนซ้ำใน C ++ มาตรฐานได้อย่างไร


คุณอาจต้องการตรวจสอบ boost.filesystem boost.org/doc/libs/1_31_0/libs/filesystem/doc/index.htm
Doug T.

1
ไม่ใช่ C ++ มาตรฐาน: pocoproject.org/docs/Poco.DirectoryIterator.html
Agnel Kurian

1
ในไม่ช้าสิ่งนี้ควรอยู่ในมาตรฐานผ่านระบบไฟล์ TSโดยมีrecursive_directory_iterator
Adi Shavit

หากการใช้ห้องสมุดมาตรฐาน C ไม่ได้รับในทางของการเรียกโปรแกรมภาษา C ++ เป็น 'มาตรฐาน' ที่nftw () นี่คือตัวอย่างที่ใช้ได้
6

2
ใครบางคนที่รู้ว่ากำลังทำอะไรควรใช้เวลาหนึ่งชั่วโมงในการอัปเดตสิ่งนี้
Josh C

คำตอบ:


99

ใน C ++ มาตรฐานในทางเทคนิคไม่มีวิธีใดที่จะทำได้เนื่องจาก C ++ มาตรฐานไม่มีแนวคิดเกี่ยวกับไดเร็กทอรี หากคุณต้องการที่จะขยายสุทธินิด ๆ หน่อย ๆ ของคุณคุณอาจต้องการที่จะมองไปที่การใช้Boost.FileSystem สิ่งนี้ได้รับการยอมรับสำหรับการรวมไว้ใน TR2 ดังนั้นสิ่งนี้จะช่วยให้คุณมีโอกาสที่ดีที่สุดในการทำให้การใช้งานของคุณใกล้เคียงกับมาตรฐานมากที่สุด

ตัวอย่างที่นำมาจากเว็บไซต์โดยตรง:

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

5
C ++ ไม่มีแนวคิดของไฟล์? แล้ว std :: fstream ล่ะ? หรือ fopen?
Kevin

30
ไฟล์ไม่ใช่ไดเร็กทอรี
1800 ข้อมูล

22
อัปเดตเกี่ยวกับเวอร์ชันบูสต์ล่าสุด: ในกรณีที่มีใครสะดุดคำตอบนี้การเพิ่มล่าสุดจะรวมถึงการเพิ่มคลาสความสะดวก :: recursive_directory_iterator ดังนั้นการเขียนลูปด้านบนด้วยการเรียกซ้ำแบบชัดแจ้งจึงไม่จำเป็นอีกต่อไป Link: boost.org/doc/libs/1_46_1/libs/filesystem/v3/doc/…
JasDev

5
VC ++ 11 มาพร้อมกับฟังก์ชันที่เหมือนกันมากในส่วนหัว <filesystem> ภายใต้ std :: tr2 :: sys namespace
mheyman

3
สิ่งนี้เคยเป็นคำตอบที่ดี แต่ตอนนี้ <filesystem> เป็นมาตรฐานแล้วควรใช้คือ (ดูตัวอย่างคำตอบอื่น ๆ )
Gathar

54

ตั้งแต่ C ++ 17 เป็นต้นไป<filesystem>ส่วนหัวและช่วงfor- คุณสามารถทำได้ง่ายๆ:

#include <filesystem>

using recursive_directory_iterator = std::filesystem::recursive_directory_iterator;
...
for (const auto& dirEntry : recursive_directory_iterator(myPath))
     std::cout << dirEntry << std::endl;

ตั้งแต่ C ++ 17 std::filesystemเป็นส่วนหนึ่งของไลบรารีมาตรฐานและสามารถพบได้ใน<filesystem>ส่วนหัว (ไม่ใช่ "การทดลอง" อีกต่อไป)


หลีกเลี่ยงการusingใช้ใช้namespaceแทน
ร้อยทั้งร้อย

2
และทำไมถึงเป็นเช่นนั้น? เฉพาะเจาะจงมากกว่าการนำสิ่งของที่คุณไม่ได้ใช้
Adi Shavit

โปรดตรวจสอบการแก้ไขของฉันฉันได้เพิ่มมาตรฐานเนมสเปซที่ขาดหายไปแล้ว
ร้อยทั้งร้อย

5
<filesystem>ไม่ใช่ TS อีกต่อไป เป็นส่วนหนึ่งของ C ++ 17 คุณควรอัปเดตคำตอบนี้ตามนั้น
IInspectable

หมายเหตุสำหรับผู้ใช้ Mac สิ่งนี้ต้องการ OSX 10.15 (Catalina) เป็นอย่างต่ำ
Justin

45

หากใช้ Win32 API คุณสามารถใช้ฟังก์ชันFindFirstFileและFindNextFile

http://msdn.microsoft.com/en-us/library/aa365200(VS.85).aspx

สำหรับการส่งผ่านไดเร็กทอรีแบบเรียกซ้ำคุณต้องตรวจสอบWIN32_FIND_DATA.dwFileAttributesแต่ละรายการเพื่อตรวจสอบว่าบิตFILE_ATTRIBUTE_DIRECTORYถูกตั้งค่าหรือไม่ หากตั้งค่าบิตคุณสามารถเรียกใช้ฟังก์ชันซ้ำกับไดเร็กทอรีนั้นได้ หรือคุณสามารถใช้สแต็กเพื่อให้เอฟเฟกต์เดียวกันของการเรียกซ้ำ แต่หลีกเลี่ยงการล้นสแต็กสำหรับทรีพา ธ ที่ยาวมาก

#include <windows.h>
#include <string>
#include <vector>
#include <stack>
#include <iostream>

using namespace std;

bool ListFiles(wstring path, wstring mask, vector<wstring>& files) {
    HANDLE hFind = INVALID_HANDLE_VALUE;
    WIN32_FIND_DATA ffd;
    wstring spec;
    stack<wstring> directories;

    directories.push(path);
    files.clear();

    while (!directories.empty()) {
        path = directories.top();
        spec = path + L"\\" + mask;
        directories.pop();

        hFind = FindFirstFile(spec.c_str(), &ffd);
        if (hFind == INVALID_HANDLE_VALUE)  {
            return false;
        } 

        do {
            if (wcscmp(ffd.cFileName, L".") != 0 && 
                wcscmp(ffd.cFileName, L"..") != 0) {
                if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                    directories.push(path + L"\\" + ffd.cFileName);
                }
                else {
                    files.push_back(path + L"\\" + ffd.cFileName);
                }
            }
        } while (FindNextFile(hFind, &ffd) != 0);

        if (GetLastError() != ERROR_NO_MORE_FILES) {
            FindClose(hFind);
            return false;
        }

        FindClose(hFind);
        hFind = INVALID_HANDLE_VALUE;
    }

    return true;
}

int main(int argc, char* argv[])
{
    vector<wstring> files;

    if (ListFiles(L"F:\\cvsrepos", L"*", files)) {
        for (vector<wstring>::iterator it = files.begin(); 
             it != files.end(); 
             ++it) {
            wcout << it->c_str() << endl;
        }
    }
    return 0;
}

19
คุณใช้เวลาเขียนนานแค่ไหน? ฉันคิดว่าจะใช้เวลาน้อยลงในการติด C ++ กับ python และทำในบรรทัดเดียว
Dustin Getz

2
นี่เป็นวิธีแก้ปัญหาที่ดีและไม่เกิดซ้ำ (ซึ่งบางครั้งก็มีประโยชน์!)
jm.

1
Btw หากใครต้องการแก้ไขโปรแกรมเล็กน้อยเพื่อยอมรับพารามิเตอร์บรรทัดคำสั่ง argv [1] สำหรับพา ธ แทนที่จะเป็นฮาร์ดโค้ด ("F: \\ cvsrepos") ลายเซ็นสำหรับ main (int, char) จะเปลี่ยนไป ถึง wmain (int, wchar_t) ดังนี้ int wmain (int argc, wchar_t * argv [])
JasDev

1
ขอบคุณ แต่ฟังก์ชันนี้ใช้ไม่ได้กับ Cyrilic มีวิธีใดบ้างที่จะทำให้มันใช้งานได้กับอักขระซิริลิกเช่น - б, в, г ฯลฯ
unresolved_external

31

คุณสามารถทำให้ง่ายขึ้นได้ด้วยC ++ 11 range ใหม่ที่ใช้forและBoost :

#include <boost/filesystem.hpp>

using namespace boost::filesystem;    
struct recursive_directory_range
{
    typedef recursive_directory_iterator iterator;
    recursive_directory_range(path p) : p_(p) {}

    iterator begin() { return recursive_directory_iterator(p_); }
    iterator end() { return recursive_directory_iterator(); }

    path p_;
};

for (auto it : recursive_directory_range(dir_path))
{
    std::cout << it << std::endl;
}

5
ไม่จำเป็นต้องเพิ่ม OP ขอมาตรฐาน c ++ โดยเฉพาะ
Craig B

23

วิธีแก้ปัญหาที่รวดเร็วคือการใช้ไลบรารีDirent.hของ C

ส่วนรหัสการทำงานจาก Wikipedia:

#include <stdio.h>
#include <dirent.h>

int listdir(const char *path) {
    struct dirent *entry;
    DIR *dp;

    dp = opendir(path);
    if (dp == NULL) {
        perror("opendir: Path does not exist or could not be read.");
        return -1;
    }

    while ((entry = readdir(dp)))
        puts(entry->d_name);

    closedir(dp);
    return 0;
}

5
กิจวัตรนี้จะไม่เกิดซ้ำ
user501138

@TimCooper แน่นอนว่ามันไม่ได้ Dirent เป็น posix ที่เฉพาะเจาะจง
Vorac

1
จริงๆแล้วมันไม่ทำงานใน VC ++ ถ้าคุณได้รับท่าเรือ dirent.h สำหรับ Visual C ++ ได้โดยโทนี่ Ronkko มันคือ FOSS ฉันเพิ่งลองสิ่งนี้และได้ผล
user1741137

10

นอกเหนือจาก boost :: filesystem ที่กล่าวมาข้างต้นแล้วคุณอาจต้องการตรวจสอบwxWidgets :: wxDirและQt :: QDir Qt

ทั้ง wxWidgets และ Qt เป็นโอเพ่นซอร์สเฟรมเวิร์ก C ++ ข้ามแพลตฟอร์ม

wxDirให้วิธีที่ยืดหยุ่นในการสำรวจไฟล์แบบวนซ้ำโดยใช้Traverse()หรือGetAllFiles()ฟังก์ชันที่ง่ายกว่า คุณสามารถใช้การข้ามผ่านด้วยGetFirst()และGetNext()ฟังก์ชันได้เช่นกัน (ฉันคิดว่า Traverse () และ GetAllFiles () เป็นเครื่องห่อที่ใช้ฟังก์ชัน GetFirst () และ GetNext () ในที่สุด)

QDirให้การเข้าถึงโครงสร้างไดเร็กทอรีและเนื้อหา มีหลายวิธีในการสำรวจไดเรกทอรีด้วย QDir คุณสามารถวนซ้ำเนื้อหาไดเร็กทอรี (รวมถึงไดเร็กทอรีย่อย) ด้วย QDirIterator ที่สร้างอินสแตนซ์ด้วยแฟล็ก QDirIterator :: Subdirectories อีกวิธีหนึ่งคือการใช้ฟังก์ชัน GetEntryList () ของ QDir และใช้การส่งผ่านแบบวนซ้ำ

นี่คือโค้ดตัวอย่าง (นำมาจากที่นี่ # ตัวอย่างที่ 8-5) ที่แสดงวิธีการวนซ้ำในไดเรกทอรีย่อยทั้งหมด

#include <qapplication.h>
#include <qdir.h>
#include <iostream>

int main( int argc, char **argv )
{
    QApplication a( argc, argv );
    QDir currentDir = QDir::current();

    currentDir.setFilter( QDir::Dirs );
    QStringList entries = currentDir.entryList();
    for( QStringList::ConstIterator entry=entries.begin(); entry!=entries.end(); ++entry) 
    {
         std::cout << *entry << std::endl;
    }
    return 0;
}

Doxygen ใช้ QT เป็นชั้นความเข้ากันได้ของระบบปฏิบัติการ เครื่องมือหลักไม่ได้ใช้ GUI เลยเป็นเพียงเนื้อหาในไดเร็กทอรี (และส่วนประกอบอื่น ๆ )
deft_code

7

Boost :: filesystem จัดเตรียม recursive_directory_iterator ซึ่งค่อนข้างสะดวกสำหรับงานนี้:

#include "boost/filesystem.hpp"
#include <iostream>

using namespace boost::filesystem;

recursive_directory_iterator end;
for (recursive_directory_iterator it("./"); it != end; ++it) {
    std::cout << *it << std::endl;                                    
}

1
ได้โปรด "มัน" คืออะไร? ไม่มีข้อผิดพลาดทางไวยากรณ์หรือไม่? และคุณเลี้ยง "จุดจบ" อย่างไร? (= รู้ได้อย่างไรว่าเราแยกวิเคราะห์ผบ. ทั้งหมด)
yO_

1
@yO_ คุณถูกต้องมีการพิมพ์ผิดตัวสร้างเริ่มต้นสำหรับ recursive_directory_iterator จะสร้างตัววนซ้ำ "ไม่ถูกต้อง" เมื่อคุณทำซ้ำเสร็จแล้วมันจะเปลี่ยนเป็น "มัน" จะไม่ถูกต้องและจะเท่ากับ "สิ้นสุด"
DikobrAz

5

คุณสามารถใช้ftw(3)หรือnftw(3)เดินตามลำดับชั้นของระบบไฟล์ใน C หรือ C ++ บนระบบPOSIX


github.com/six-k/dtreetrawl/blob/…มีตัวอย่างนี้ โค้ดทำสิ่งต่างๆได้อีกเล็กน้อย แต่ทำหน้าที่เป็นบทช่วยสอนที่ดีสำหรับnftw()การใช้งาน
6 ก

4

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

ดูเอกสาร OS API ของคุณสำหรับวิธีการดำเนินการนี้ หากคุณต้องการพกพาคุณจะต้องมี#ifdef จำนวนมากสำหรับระบบปฏิบัติการต่างๆ


4

คุณน่าจะดีที่สุดกับระบบไฟล์ทดลองของ boost หรือ c ++ 14 หากคุณกำลังแยกวิเคราะห์ไดเร็กทอรีภายใน (เช่นใช้สำหรับโปรแกรมของคุณเพื่อจัดเก็บข้อมูลหลังจากปิดโปรแกรมแล้ว) ให้สร้างไฟล์ดัชนีที่มีดัชนีของเนื้อหาไฟล์ อย่างไรก็ตามคุณอาจต้องใช้บูสต์ในอนาคตดังนั้นหากคุณไม่ได้ติดตั้งให้ติดตั้ง! ประการที่สองคุณสามารถใช้การรวบรวมแบบมีเงื่อนไขเช่น:

#ifdef WINDOWS //define WINDOWS in your code to compile for windows
#endif

รหัสสำหรับแต่ละกรณีนำมาจากhttps://stackoverflow.com/a/67336/7077165

#ifdef POSIX //unix, linux, etc.
#include <stdio.h>
#include <dirent.h>

int listdir(const char *path) {
    struct dirent *entry;
    DIR *dp;

    dp = opendir(path);
    if (dp == NULL) {
        perror("opendir: Path does not exist or could not be read.");
        return -1;
    }

    while ((entry = readdir(dp)))
        puts(entry->d_name);

    closedir(dp);
    return 0;
}
#endif
#ifdef WINDOWS
#include <windows.h>
#include <string>
#include <vector>
#include <stack>
#include <iostream>

using namespace std;

bool ListFiles(wstring path, wstring mask, vector<wstring>& files) {
    HANDLE hFind = INVALID_HANDLE_VALUE;
    WIN32_FIND_DATA ffd;
    wstring spec;
    stack<wstring> directories;

    directories.push(path);
    files.clear();

    while (!directories.empty()) {
        path = directories.top();
        spec = path + L"\\" + mask;
        directories.pop();

        hFind = FindFirstFile(spec.c_str(), &ffd);
        if (hFind == INVALID_HANDLE_VALUE)  {
            return false;
        } 

        do {
            if (wcscmp(ffd.cFileName, L".") != 0 && 
                wcscmp(ffd.cFileName, L"..") != 0) {
                if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                    directories.push(path + L"\\" + ffd.cFileName);
                }
                else {
                    files.push_back(path + L"\\" + ffd.cFileName);
                }
            }
        } while (FindNextFile(hFind, &ffd) != 0);

        if (GetLastError() != ERROR_NO_MORE_FILES) {
            FindClose(hFind);
            return false;
        }

        FindClose(hFind);
        hFind = INVALID_HANDLE_VALUE;
    }

    return true;
}
#endif
//so on and so forth.

2

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


แล้ว C ++ ล่ะ? มีฟังก์ชั่นดังกล่าวใน iostream หรือไม่?
Aaron Maenpaa

2
สำหรับไฟล์เท่านั้น ไม่มีฟังก์ชัน "แสดงไฟล์ทั้งหมดในไดเรกทอรี" ใด ๆ
1800 ข้อมูล

1
@ 1800: ไดเรกทอรีคือไฟล์
Lightness Races ใน Orbit

2

เราอยู่ในปี 2019 เรามีไลบรารีมาตรฐานระบบไฟล์ในC++. Filesystem libraryให้สิ่งอำนวยความสะดวกสำหรับการดำเนินการดำเนินการบนระบบไฟล์และส่วนประกอบของพวกเขาเช่นเส้นทางไฟล์ปกติและไดเรกทอรี

มีหมายเหตุสำคัญในลิงก์นี้หากคุณกำลังพิจารณาปัญหาการพกพา มันบอกว่า:

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

ไลบรารีระบบไฟล์ได้รับการพัฒนาboost.filesystemโดยเผยแพร่เป็นข้อกำหนดทางเทคนิค ISO / IEC TS 18822: 2015 และในที่สุดก็รวมเข้ากับ ISO C ++ ณ C ++ 17 ขณะนี้การใช้งานบูสต์มีให้บริการในคอมไพเลอร์และแพลตฟอร์มมากกว่าไลบรารี C ++ 17

@ adi-shavit ได้ตอบคำถามนี้เมื่อเป็นส่วนหนึ่งของ std :: trial และเขาได้อัปเดตคำตอบนี้ในปี 2017 ฉันต้องการให้รายละเอียดเพิ่มเติมเกี่ยวกับห้องสมุดและแสดงตัวอย่างโดยละเอียดเพิ่มเติม

std :: filesystem :: recursive_directory_iteratorคือการLegacyInputIteratorวนซ้ำบนองค์ประกอบ directory_entry ของไดเร็กทอรีและวนซ้ำบนรายการของไดเร็กทอรีย่อยทั้งหมด ลำดับการวนซ้ำไม่ได้ระบุไว้ยกเว้นว่าแต่ละรายการไดเร็กทอรีจะถูกเยี่ยมชมเพียงครั้งเดียว

หากคุณไม่ต้องการวนซ้ำในรายการของไดเรกทอรีย่อยควรใช้directory_iterator

ทั้งสอง iterators ส่งกลับวัตถุของdirectory_entry directory_entryมีฟังก์ชั่นสมาชิกที่มีประโยชน์ต่างๆเช่นis_regular_file, is_directory, is_socket, is_symlinkฯลฯpath()ฟังก์ชันสมาชิกส่งกลับวัตถุของมาตรฐาน :: ระบบแฟ้ม :: เส้นทางและมันสามารถนำมาใช้เพื่อให้ได้file extension, filename,root name ,

ลองพิจารณาตัวอย่างด้านล่าง ฉันใช้Ubuntuและรวบรวมผ่านเทอร์มินัลโดยใช้ไฟล์

g ++ example.cpp --std = c ++ 17 -lstdc ++ fs -Wall

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

void listFiles(std::string path)
{
    for (auto& dirEntry: std::filesystem::recursive_directory_iterator(path)) {
        if (!dirEntry.is_regular_file()) {
            std::cout << "Directory: " << dirEntry.path() << std::endl;
            continue;
        }
        std::filesystem::path file = dirEntry.path();
        std::cout << "Filename: " << file.filename() << " extension: " << file.extension() << std::endl;

    }
}

int main()
{
    listFiles("./");
    return 0;
}

1

คุณไม่ทำ C ++ มาตรฐานไม่เปิดเผยแนวคิดของไดเร็กทอรี โดยเฉพาะอย่างยิ่งมันไม่ได้ให้วิธีใด ๆ ในการแสดงรายการไฟล์ทั้งหมดในไดเรกทอรี

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


1

คุณสามารถใช้std::filesystem::recursive_directory_iterator. แต่ระวังสิ่งนี้รวมถึงลิงก์สัญลักษณ์ (อ่อน) is_symlinkหากคุณต้องการที่จะหลีกเลี่ยงพวกเขาคุณสามารถใช้ ตัวอย่างการใช้งาน:

size_t directorySize(const std::filesystem::path& directory)
{
    size_t size{ 0 };
    for (const auto& entry : std::filesystem::recursive_directory_iterator(directory))
    {
        if (entry.is_regular_file() && !entry.is_symlink())
        {
            size += entry.file_size();
        }
    }
    return size;
}

1
สุดท้าย แต่ไม่ท้ายสุดจริง ๆ แล้วดีกว่าคำตอบก่อนหน้านี้
Seyed Mehran Siadati

0

หากคุณใช้ Windows คุณสามารถใช้ FindFirstFile ร่วมกับ FindNextFile API คุณสามารถใช้ FindFileData.dwFileAttributes เพื่อตรวจสอบว่าพา ธ ที่กำหนดเป็นไฟล์หรือไดเร็กทอรี หากเป็นไดเรกทอรีคุณสามารถทำซ้ำอัลกอริทึมซ้ำได้

ที่นี่ฉันได้รวบรวมรหัสที่แสดงรายการไฟล์ทั้งหมดบนเครื่อง Windows

http://dreams-soft.com/projects/traverse-directory


0

File tree walk ftwเป็นวิธีการวนซ้ำในการสร้างไดเร็กทอรีไดเร็กทอรีทั้งหมดในพา ธ รายละเอียดเพิ่มเติมที่นี่

หมายเหตุ: คุณยังสามารถใช้ftsที่สามารถข้ามไฟล์ที่ซ่อนอยู่เช่น.หรือ..หรือ.bashrc

#include <ftw.h>
#include <stdio.h>
#include <sys/stat.h>
#include <string.h>

 
int list(const char *name, const struct stat *status, int type)
{
     if (type == FTW_NS)
     {
         return 0;
     }

     if (type == FTW_F)
     {
         printf("0%3o\t%s\n", status->st_mode&0777, name);
     }

     if (type == FTW_D && strcmp(".", name) != 0)
     {
         printf("0%3o\t%s/\n", status->st_mode&0777, name);
     }
     return 0;
}

int main(int argc, char *argv[])
{
     if(argc == 1)
     {
         ftw(".", list, 1);
     }
     else
     {
         ftw(argv[1], list, 1);
     }

     return 0;
}

ผลลัพธ์มีลักษณะดังนี้:

0755    ./Shivaji/
0644    ./Shivaji/20200516_204454.png
0644    ./Shivaji/20200527_160408.png
0644    ./Shivaji/20200527_160352.png
0644    ./Shivaji/20200520_174754.png
0644    ./Shivaji/20200520_180103.png
0755    ./Saif/
0644    ./Saif/Snapchat-1751229005.jpg
0644    ./Saif/Snapchat-1356123194.jpg
0644    ./Saif/Snapchat-613911286.jpg
0644    ./Saif/Snapchat-107742096.jpg
0755    ./Milind/
0644    ./Milind/IMG_1828.JPG
0644    ./Milind/IMG_1839.JPG
0644    ./Milind/IMG_1825.JPG
0644    ./Milind/IMG_1831.JPG
0644    ./Milind/IMG_1840.JPG

ขอให้เราบอกว่าถ้าคุณต้องการเพื่อให้ตรงกับชื่อไฟล์ (ตัวอย่าง: การค้นหาทั้งหมด*.jpg, *.jpeg, *.png. ไฟล์) fnmatchสำหรับความต้องการที่เฉพาะเจาะจงใช้

 #include <ftw.h>
 #include <stdio.h>
 #include <sys/stat.h>
 #include <iostream>
 #include <fnmatch.h>

 static const char *filters[] = {
     "*.jpg", "*.jpeg", "*.png"
 };

 int list(const char *name, const struct stat *status, int type)
 {
     if (type == FTW_NS)
     {
         return 0;
     }

     if (type == FTW_F)
     {
         int i;
         for (i = 0; i < sizeof(filters) / sizeof(filters[0]); i++) {
             /* if the filename matches the filter, */
             if (fnmatch(filters[i], name, FNM_CASEFOLD) == 0) {
                 printf("0%3o\t%s\n", status->st_mode&0777, name);
                 break;
             }
         }
     }

     if (type == FTW_D && strcmp(".", name) != 0)
     {
         //printf("0%3o\t%s/\n", status->st_mode&0777, name);
     }
     return 0;
 }

 int main(int argc, char *argv[])
 {
     if(argc == 1)
     {
         ftw(".", list, 1);
     }
     else
     {
         ftw(argv[1], list, 1);
     }

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