tags:

views:

509

answers:

4
+6  Q: 

File Glob in C++

What's the C++ way of Perl's idiom:

my @files = glob("file*.txt");
foreach my $file (@files) {

   # process $file
}
A: 

You can mimic the "glob" using fnmatch. But you'll need to open the directory, read the contents, and match each entry using fnmatch.

No direct equivalent that's standard AFAIK.

xyld
What? POSIX isn't a good enough standard?
Ken Bloom
+6  A: 

There's no standard C++ way to emulate this because there is no standard C++ functionality of reading the contents of a directory. What you can do is use Boost.Filesystem:

#include <boost/filesystem.hpp> // plus iostream,algorithm,string,iterator
using namespace boost::filesystem; // and std

struct pathname_of {
    string operator()(const directory_entry& p) const {
        return p.path().filename(); // or your creativity here
    }
};

int main(int argc, char* argv[])
{
    transform(directory_iterator("."), directory_iterator(),
              ostream_iterator<string>(cout, "\n"),
              pathname_of());
    return 0;
}
wilhelmtell
Is there ANYTHING boost can't do?!?!
DVK
@Wilhelm: Thanks. How do you compile that? I tried this but failed `g++ -I ~/.boost/include/boost-1_38 wiltell_code.cpp -o wiltell_code`
neversaint
What error do you get? Compiler, linker? Make sure you add the missing include: `<algorithm>`. Say `std::for_each()` or add a `using` statement. Are you on Linux or Mac? If you're on Linux make sure you link against `boost_filesystem`. With g++ you can say `-lboost_filesystem`. If you're on a Mac you probably also need to link against `boost_system`.
wilhelmtell
I updated the example to something more useful, something that would give some output. Also I added in comment the code you must add for the thing to compile. Remember to add `-lboost_filesystem` (and `-lboost_system` if you're on a Mac like yours truly) when you run g++. When you run the executable you should get a listing of the files and directory under the current directory.
wilhelmtell
@Wil: Thanks, `-lboost_system` works like charm
neversaint
How does this code process only files that match the glob "file*.txt"?
Dan Hook
It doesn't; it processes all files. I was just illustrating how to traverse a filesystem. If you want to filter out certain files then you can use a (non-standard) `copy_if()` algorithm rather than `transform()`. You then provide the algorithm a predicate which decides whether to process a given filename or not. You can use Boost.Regex for the predicate, and that would give you much more power than globbing. I don't think Boost has a glob function, but you can use the POSIX `fnmatch()`, or Windows' `PathMatchSpecEx()`.
wilhelmtell
If you're going to do that a lot then you might write a `filtered_directory_iterator` to extend Boost's filesystem library. This would make the calling code somewhat less cryptic.
wilhelmtell
+1  A: 

Call me old school.

f = popen("ls file*.txt", "r");

Wayne
I call it unnecessary... uses `fork()` and `exec()` along with a bunch of others all for something that should take only one system call
xyld
+12  A: 

The POSIX API specifies the glob() and globfree() functions for this. See the man page. wordexp() and wordfree(), also specified by POSIX, support other kinds of expansions as well.

Ken Bloom
Hah, no kidding... It does. Thanks for posting that!
xyld