1

How to get a list of all files with a specific extension with c++ without <dirent.h> on windows. dirent.h is not working on visual studio 2019, is there any other way i could get a list of all files in a directory.

for example of the list would be

file.txt
secode.txt
hello.txt
h.txt

if not then could i get dirent.h working in visual studio 2019.

Insane Miner
  • 122
  • 10
  • Use [``](https://en.cppreference.com/w/cpp/filesystem) if your compiler is new enough. If not, you probably want [`FindFirstFile`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstfilea) or [`FindFirstFileExA`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstfileexa) along with the matching`FindNextFile`. – user4581301 Dec 24 '19 at 07:19
  • For the `` version, look at [`std::filesystem::directory_iterator`](https://en.cppreference.com/w/cpp/filesystem/directory_iterator). Good usage example at the bottom of the page. The `FindFirstFile` brothers are well documented at the given links, complete with examples. – user4581301 Dec 24 '19 at 07:32
  • 1
    Does this answer your question? [How to work ith file system using c++](https://stackoverflow.com/questions/43900462/how-to-work-ith-file-system-using-c) – rezaebrh Dec 24 '19 at 07:36
  • The mentioned dupe is not referring to extensions. And the dupes accepted-answer is using "dirent.h". Another example of a bad judgement by the guardians of the grail. – A M Dec 24 '19 at 21:53

2 Answers2

2

With C++17 this is also easily possible without boost. I tested the below example with VS2019.

Please see the example below. Reading the complete file list is just a very short one-liner:

std::vector fileList (fs::directory_iterator(startPath), {});

Usage of range constructor for std::vector.

We can define the std::vector without template argument. The compiler can deduce the argument from the given function parameters. This feature is called CTAD ("class template argument deduction").

Additionally, you can see that I do not use the "end()"-iterator explicitely.

This iterator will be constructed from the empty brace-enclosed initializer list with the correct type, because it will be deduced to be the same as the type of the first argument due to the std::vector constructor requiring that.

Of course you could also check sub directories with the fs::recursive_directory_iterator

Finding the extension is then quite simple. You can of course check additional file/path attributes as well. No problem.

Please see a complete working example:

#include <iostream>
#include <filesystem>
#include <vector>
#include <iterator>

namespace fs = std::filesystem;

int main() {

    // The start path
    const fs::path startPath{ "C:\\temp\\" };
    // And the extension to look for
    const std::string extension{ ".txt" };

    // Get all directory entries into our fileList vector
    std::vector fileList (fs::directory_iterator(startPath), {});

    // Evaluate. Go through all directory entries
    for (const fs::directory_entry& de : fileList) {

        // Get path as string
        std::string p{ de.path().string() };

        // Check if it ends with the given extension
        if (p.substr(p.size() - extension.size(), extension.size()) == extension)
            std::cout << p << "\n";
    }
    return 0;
}

Additional solution using std::transform and std::copy_if:

#include <iostream>
#include <filesystem>
#include <vector>
#include <iterator>

namespace fs = std::filesystem;

int main() {

    // The start path
    const fs::path startPath{ "C:\\temp\\" };
    // And the extension to look for
    const std::string extension{ ".txt" };

    std::vector<std::string> files{};

    // Get all path names as string
    std::transform(fs::directory_iterator(startPath), {}, std::back_inserter(files), [](const fs::directory_entry & de) { return de.path().string(); });

    // Output all files with extension
    std::copy_if(files.begin(), files.end(), std::ostream_iterator<std::string>(std::cout,"\n"), [&extension](const std::string & p) {
        return (p.substr(p.size() - extension.size(), extension.size()) == extension); });

    return 0;
}
A M
  • 14,694
  • 5
  • 19
  • 44
1

if you have boost you can use boost::filesystem here is an example of getting all image in jpg extension.

#include <boost/filesystem.hpp>
#include <boost/filesystem/path.hpp>
#include <vector>
#include <string>
using namespace boost::filesystem;
using std::string;
using std::vector;
    void GetAllImageFromDir(path& dir, vector<path>& all_dir_images)
{
    string str(".jpg");             // store paths,
    vector<path> all_dir_files;

    std::copy(directory_iterator(dir), directory_iterator(), back_inserter(all_dir_files));

    for (int k = 0; k < all_dir_files.size(); ++k )
    {

        if (all_dir_files[k].filename_is_dot() || all_dir_files[k].filename_is_dot_dot() || !is_regular_file(all_dir_files[k]))
        {
            continue;
        }
        else
        {
            if (is_regular_file(all_dir_files[k]))
            {
                string extension = boost::filesystem::extension(all_dir_files[k].string());

                    if (extension.compare(str) == 0)
                    {
                        all_dir_images.push_back(all_dir_files[k]);
                    }
            }
        }
    }
}
alon
  • 220
  • 1
  • 16