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
Splitting a String by a Character
How to Detect Double Precision Floating Point Overflow and Underflow
How to Guarantee Order of Argument Evaluation When Calling a Function Object
C++ For-Loop - Size_Type VS. Size_T
Trouble with Inheritance of Operator= in C++
Forward Declaration with Unique_Ptr
Accessing Environment Variables in C++
Why Does This Delay-Loop Start to Run Faster After Several Iterations with No Sleep
How to Avoid Precompiled Headers
May Std::Vector Make Use of Small Buffer Optimization
C++: Safe to Use Longjmp and Setjmp
Ctrl + C Interrupt Event Handling in Linux
C++ Object Size with Virtual Methods
How to Get the CPU Usage Per Thread on Windows (Win32)
Convert Wstring to String Encoded in Utf-8
Convert Std::Tuple to Std::Array C++11
Microsecond Resolution Timestamps on Windows
Prevent User Process from Being Killed with "End Process" from Process Explorer