implement a recursive dir iterator

Oct 27, 2013 at 9:16am
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
Oct 28, 2013 at 7:57am
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
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
Clearly you need to remember the filter so you can make up the correct wildcard in step 4b above.
Topic archived. No new replies allowed.