How to Use a Mask to Iterate Files in a Directory with Boost

Can I use a mask to iterate files in a directory with Boost?

EDIT: As noted in the comments, the code below is valid for versions of boost::filesystem prior to v3. For v3, refer to the suggestions in the comments.


boost::filesystem does not have wildcard search, you have to filter files yourself.

This is a code sample extracting the content of a directory with a boost::filesystem's directory_iterator and filtering it with boost::regex:

const std::string target_path( "/my/directory/" );
const boost::regex my_filter( "somefiles.*\.txt" );

std::vector< std::string > all_matching_files;

boost::filesystem::directory_iterator end_itr; // Default ctor yields past-the-end
for( boost::filesystem::directory_iterator i( target_path ); i != end_itr; ++i )
{
// Skip if not a file
if( !boost::filesystem::is_regular_file( i->status() ) ) continue;

boost::smatch what;

// Skip if no match for V2:
if( !boost::regex_match( i->leaf(), what, my_filter ) ) continue;
// For V3:
//if( !boost::regex_match( i->path().filename().string(), what, my_filter ) ) continue;

// File matches, store it
all_matching_files.push_back( i->leaf() );
}

(If you are looking for a ready-to-use class with builtin directory filtering, have a look at Qt's QDir.)

Iterating files with boost::filesystem 3.0

Try

i->path().filename().string()

this is the equivalent for i->leaf() in boost::filesystem 3.0

In your code:

// Skip if no match
if( !boost::regex_match( i->path().filename().string(), what, my_filter ) )
continue;

// File matches, store it
all_matching_files.push_back( i->path().filename().string() );

use boost to return file in a directory

To access the file/directory names placed n a particular boost::path instance you have, use boosts directory_iterator, as shown in the linked example.

To check for particular file-/directory name signatures found from iterating, boost::regex might come in handy.

How do you iterate through every file/directory recursively in standard C++?

In standard C++, technically there is no way to do this since standard C++ has no conception of directories. If you want to expand your net a little bit, you might like to look at using Boost.FileSystem. This has been accepted for inclusion in TR2, so this gives you the best chance of keeping your implementation as close as possible to the standard.

An example, taken straight from the website:

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

How to get list of files with a specific extension in a given folder?

#define BOOST_FILESYSTEM_VERSION 3
#define BOOST_FILESYSTEM_NO_DEPRECATED
#include <boost/filesystem.hpp>

namespace fs = boost::filesystem;

/**
* \brief Return the filenames of all files that have the specified extension
* in the specified directory and all subdirectories.
*/
std::vector<fs::path> get_all(fs::path const & root, std::string const & ext)
{
std::vector<fs::path> paths;

if (fs::exists(root) && fs::is_directory(root))
{
for (auto const & entry : fs::recursive_directory_iterator(root))
{
if (fs::is_regular_file(entry) && entry.path().extension() == ext)
paths.emplace_back(entry.path().filename());
}
}

return paths;
}

Basic concepts with std::string references, std::regex and boost::filesystem

std::smatch doesn't store a copy of the characters comprising the match, but only pairs of iterators into the original string that was searched.

The first fragment passes a temporary string to std::regex_match. By the time you get around to examining matches, that string is gone and the iterators held by matches are all dangling. The program then exhibits undefined behavior by trying to use them.

In the second fragment, the string passed to std::regex_match is still alive by the time matches is used, so all is well.


Note 1: That the problem manifests differently depending on file name length is likely due to small string optimization. It's common for std::string implementations to reserve a small buffer in the class instance, and store short strings there; whereas longer strings are allocated on the heap. It's possible that the stack space previously occupied by the temp string is still intact, while the heap space has been reused for other allocations. The program exhibits undefined behavior either way - "seems to work" is one possible manifestation of UB.


Note 2: It doesn't matter much whether path::string() returns by value or by reference. path::filename() returns by value, so dir_it.path().filename().string() would get destroyed too early either way, whether it's a member of a temporary dir_it.path().filename() object, or manufactured on the fly by string().

C++ How to Find Files Using Path With Multiple Wildcards

You can use boost::filesystem. here a link to the library: http://www.boost.org/doc/libs/1_57_0/libs/filesystem/doc/index.htm

you can iterate on a path. You can declare a regular expression boost::regexp and pass it to the boost::filesystem::path.

How can I get the list of files in a directory using C or C++?

UPDATE 2017:

In C++17 there is now an official way to list files of your file system: std::filesystem. There is an excellent answer from Shreevardhan below with this source code:

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

Old Answer:

In small and simple tasks I do not use boost, I use dirent.h. It is available as a standard header in UNIX, and also available for Windows via a compatibility layer created by Toni Ronkko.

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

It is just a small header file and does most of the simple stuff you need without using a big template-based approach like boost (no offence, I like boost!).



Related Topics



Leave a reply



Submit