遍历目录的类(广度优先),本来想找一段代码了事,后来没发现合适的,自己写了一个,分享给大家。其中用到一个线程类,也是自己封装的,与主题无关不贴出来,有需要的话去我的资源里找吧。
directory_traversal.h文件
#ifndef DIRECTORY_TRAVERSAL_H__
#define DIRECTORY_TRAVERSAL_H__
#include
#include
#include "hthread.h"
struct FileInfo{
FileInfo();
FileInfo(const FileInfo&);
FileInfo& operator=(const FileInfo&);
WIN32_FIND_DATAW file_data;
wchar_t path[MAX_PATH];
size_t level;
};
int MakePath(wchar_t* file_path, size_t size, const wchar_t* parent_path, const wchar_t* file_name);
FileInfo MakeFileInfo(const wchar_t* parent_path, size_t level, const WIN32_FIND_DATA& cur_fd);
class DirectoryTraversal
{
public:
typedef bool (*callback_find)(const FileInfo* , void*);
typedef void (*callback_complete)(bool , void*);
DirectoryTraversal();
virtual ~DirectoryTraversal();
// 设置遍历参数
void SetCallback(callback_find cb_find, void* p1, callback_complete cb_complete, void* p2);
// 启动遍历线程
int Start(const wchar_t* begin_path, size_t max_level);
int BreadthFirstTravers(const wchar_t* begin_path, size_t max_level);
void SetStopFlag();
private:
static unsigned int __stdcall ThreadTravers(void* lp);
// 用递归方法,遍历d:\\w导致栈溢出
//int BreadthFirstTravers(const wchar_t* path, size_t level);
/*
如果cb_find返回bool型, 一般应返回true, 如果返回false且当前文件是目录, 则不遍历此目录下的文件
p作为cb_find的参数.
*/
HANDLE FindFirstSubFile(const wchar_t* path, WIN32_FIND_DATA* fd);
protected:
wchar_t begin_path_[MAX_PATH];
size_t max_level_; // 遍历级数
bool stop_;
callback_find cb_find_;
void* find_para_;
callback_complete cb_complete_;
void* complete_para_;
HThread thread_;
std::queue folder_queue_;
};
#endif
#include
#include
#include
#include
#include "directory_traversal.h"
#pragma comment(lib,"shlwapi.lib")
FileInfo::FileInfo()
{
level = 0;
memset(path, 0, sizeof(path));
}
FileInfo::FileInfo(const FileInfo& r)
{
this->file_data = r.file_data;
wcscpy_s(this->path, MAX_PATH, r.path);
this->level = r.level;
}
FileInfo& FileInfo::operator=(const FileInfo& r)
{
if(&r != this)
{
this->file_data = r.file_data;
wcscpy_s(this->path, MAX_PATH, r.path);
this->level = r.level;
}
return *this;
}
int MakePath(wchar_t* file_path, size_t size, const wchar_t* parent_path, const wchar_t* file_name)
{
int ret = wcscpy_s(file_path, size, parent_path);
if (0 == ret)
ret = PathAppendW(file_path, file_name) ? 0 : -1;
return ret;
}
FileInfo MakeFileInfo(const wchar_t* parent_path, size_t level, const WIN32_FIND_DATAW& cur_fd)
{
FileInfo cur_folder;
MakePath(cur_folder.path, MAX_PATH, parent_path, cur_fd.cFileName);
cur_folder.file_data = cur_fd;
cur_folder.level = level;
return cur_folder;
}
DirectoryTraversal::DirectoryTraversal() : stop_(false)
{}
DirectoryTraversal::~DirectoryTraversal()
{
thread_.WaitExit();
}
void DirectoryTraversal::SetCallback(callback_find cb_find, void* p1, callback_complete cb_complete, void* p2)
{
cb_find_ = cb_find;
find_para_ = p1;
cb_complete_ = cb_complete;
complete_para_ = p2;
}
int DirectoryTraversal::Start(const wchar_t* begin_path, size_t max_level)
{
stop_ = false;
wcscpy_s(begin_path_, MAX_PATH, begin_path); // 线程启动前要保存传入的数据
max_level_ = max_level;
thread_.Start(&DirectoryTraversal::ThreadTravers, this);
return 0;
}
unsigned int __stdcall DirectoryTraversal::ThreadTravers(void* lp)
{
DirectoryTraversal* self = (DirectoryTraversal*)lp;
if(wcslen(self->begin_path_) == 0)
return -1;
return self->BreadthFirstTravers(self->begin_path_, self->max_level_);
}
int DirectoryTraversal::BreadthFirstTravers(const wchar_t* begin_path, size_t max_level)
{
while(!folder_queue_.empty())
folder_queue_.pop();
HANDLE find_file = INVALID_HANDLE_VALUE;
WIN32_FIND_DATAW fd;
wchar_t cur_path[MAX_PATH];
wcscpy_s(cur_path, MAX_PATH, begin_path);
size_t cur_level = 1;
do {
if (max_level > 0 && cur_level > max_level) {
if (cb_complete_)
(*cb_complete_)(stop_, complete_para_);
return 0;
}
find_file = FindFirstSubFile(cur_path, &fd);
if (INVALID_HANDLE_VALUE == find_file)
{
assert(false);
if (cb_complete_)
(*cb_complete_)(stop_, complete_para_);
return -1;
}
FileInfo new_find_file;
do {
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
new_find_file = MakeFileInfo(cur_path, cur_level, fd);
if(cb_find_)
(*cb_find_)(&new_find_file, find_para_);
}
else {
if(!(fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) &&
0 != wcscmp(fd.cFileName, L".") && 0 != wcscmp(fd.cFileName, L"..")) {
new_find_file = MakeFileInfo(cur_path, cur_level, fd);
if(cb_find_){
if((*cb_find_)(&new_find_file, find_para_))
folder_queue_.push(new_find_file);
}
else
folder_queue_.push(new_find_file);
}
}
if (stop_) break;
} while(FindNextFileW(find_file, &fd));
FindClose(find_file);
if(stop_ || folder_queue_.empty()) {
if (cb_complete_)
(*cb_complete_)(stop_, complete_para_);
return 0;
}
FileInfo next_folder = folder_queue_.front();
folder_queue_.pop();
cur_level = next_folder.level + 1;
wcscpy_s(cur_path, MAX_PATH, next_folder.path);
} while(true);
}
void DirectoryTraversal::SetStopFlag()
{
stop_ = true;
}
HANDLE DirectoryTraversal::FindFirstSubFile(const wchar_t* path, WIN32_FIND_DATAW* fd)
{
wchar_t buffer[MAX_PATH];
wcscpy_s(buffer, MAX_PATH, path);
if(!PathAppendW(buffer, L"*.*"))
return NULL;
return FindFirstFileW(buffer, fd);
}