Oct 27, 2013 at 9:16am UTC
Hi,
I want to write a recursive dir iterator, so I can write code like:
for_each(recursive_dir_iter("c:/" , "*.txt" ), recursive_dir_iter(), display_func);
I've been googling for a while, there are articles about non-recursive dir iterator, like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
#pragma once
#include <windows.h>
#include <string>
#include <algorithm>
#include <memory>
using namespace std;
struct file_info {
bool is_dir;
string name;
file_info() {}
file_info(const WIN32_FIND_DATA& x)
: is_dir((FILE_ATTRIBUTE_DIRECTORY & x.dwFileAttributes) == FILE_ATTRIBUTE_DIRECTORY)
, name(x.cFileName)
{}
};
template <typename value_t>
struct file_iter : public iterator<input_iterator_tag, value_t> {
typedef file_iter<value_t> self_t;
bool end_;
string path_;
string pattern_;
value_t value_;
WIN32_FIND_DATA ffd_;
shared_ptr<void > hfind_; // HANDLE is defined as void* in SDK
file_iter() : end_(true ) {
}
file_iter(const string& path, const string& pattern)
: end_(false )
, path_(path)
, pattern_(pattern)
{
hfind_ = shared_ptr<void >(FindFirstFile((path_ + pattern_).c_str(), &ffd_), ::FindClose);
if (hfind_.get() == INVALID_HANDLE_VALUE) {
end_ = true ;
} else {
value_ = value_t(ffd_);
}
}
void next() {
if (FindNextFile(hfind_.get(), &ffd_)) {
value_ = value_t(ffd_);
} else {
end_ = true ;
}
}
const value_t& operator *() {
return value_;
}
const value_t* operator ->() {
return &(operator *());
}
file_iter& operator ++() {
next();
return *this ;
}
bool equal(const file_iter<value_t>& x) const {
if (end_ && x.end_) {
return true ;
}
return (strcmp(ffd_.cFileName, x.ffd_.cFileName) == 0
&& hfind_ == x.hfind_
&& path_ == x.path_
&& pattern_ == x.pattern_);
}
};
template <typename value_t>
inline bool operator ==(const file_iter<value_t>& x, const file_iter<value_t>& y)
{
return x.equal(y);
}
template <typename value_t>
inline bool operator !=(const file_iter<value_t>& x, const file_iter<value_t>& y)
{
return !x.equal(y);
}
anyone has been working on this before? How to make it recursive.
Thanks in advance.
Last edited on Oct 27, 2013 at 9:17am UTC
Oct 28, 2013 at 7:57am UTC
Think about what you'd do if you where using the native OS call to do recursive traversal.
1. You use FindFirstFile/FindNextFile to get each entry.
2. You'd check the type of the entry.
3. If it's a normal file, you pass it to the caller.
4. If it's a directory:
a. you stash your current context (in the call stack)
b. make up the new name
c. do the whole FindFirstFile/FindNextFile thing all over again.
d. pop the stack and continue
Your iterator should do the same. So, for example, you ought to have a stack of WIN32_FIND_DATA in your iterator.
Oct 28, 2013 at 9:45am UTC
Thanks,
At first I use the first parameter of FindFirstFile, it handles the pattern, eg: *atl*.dll ,
but now the pattern must be "*", so it could search for directories, now I need to do the filtering
Oct 28, 2013 at 1:44pm UTC
Clearly you need to remember the filter so you can make up the correct wildcard in step 4b above.