[WIN32|STL]C++实现python的os模块的walk函数
大家在学习python过程中,应该也遇到使用遍历目录的功能。可能是作业或者其他的,既然是python,肯定是用轮子就对了!!
在python中,遍历一个目录可以使用,os.list配合os.chdir一起使用遍历目录,但是这可是python,还有一个函数就是os.walk。
先放一张图来装X~~~上面有walk函数的用途,以及每个参数的含义。
粗略来说就是:给定一个目录,然后walk函数去遍历它。遍历的结果为目录,也有可能是文件,结果会以(目录字符串,子目录名字符串列表,目录下文件名字符串列表)这样的元组的方式存在一张列表里。
ok!这就是功能与要求,额外的功能就是这些个元素按照怎么样的顺序存在这个结果列表里(源代码中的topdown)。
下面是全部源代码:
/***************************************************
*作者: 小冰
*邮箱: lovingxiaobing@qq.com
*备注: 遍历目录的结果保存到STL容器中
* 函数的功能类似Python的os模块的walk函数
***************************************************/
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _UNICODE
#define _UNICODE
#endif
#include <tchar.h>
#include <Windows.h>
#include <string>
#include <tuple>
#include <list>
#include <algorithm>
#include <iostream>
#if defined(UNICODE) || defined(_UNICODE)
#define str std::wstring
#define get_input(value) std::wcin>>value
#else
#define str std::string
#define get_input(value) std::cin>>value
#endif
using std::endl;
using std::list;
using std::tuple;
using std::make_tuple;
using std::for_each;
typedef tuple<str,list<str>,list<str>> walk_list_element_type;
typedef list<walk_list_element_type> walk_list;
void walk( str& path, walk_list& rtn_list, bool topdown=true ) {
DWORD dwFileAttr = GetFileAttributes(path.c_str());
if ( INVALID_FILE_ATTRIBUTES != dwFileAttr ) {
/// 只有是目录才遍历
if ( (FILE_ATTRIBUTE_DIRECTORY & dwFileAttr) == FILE_ATTRIBUTE_DIRECTORY ) {
WIN32_FIND_DATA wfd;
/// 开始搜索
HANDLE handle = FindFirstFile((path + str(_T("\\*"))).c_str(), &wfd);
if ( INVALID_HANDLE_VALUE != handle ) {
size_t times = 2;
str _path_file = path + str(_T("\\"));
list<str> directorys;
list<str> files;
/// 搜索下一个
while ( FindNextFile(handle, &wfd) ) {
str name = str(wfd.cFileName);
if ( (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY ) {
// 每个目录中只有一个 . 和 .. 目录, 过滤完了2次也就完了
// 还有一个问题就是如果目录很多,数量可以达到size_t所能容大的数的大小也没关系
// 因为即使那么多目录,也就使用2次lstrcmp,再次重新进入下一轮的--,所以忽略不计
// 总比一直调用函数效率高!
if ( times-- ) {
if ( !lstrcmp(wfd.cFileName, _T(".")) || !lstrcmp(wfd.cFileName, _T("..")) )
continue;
}
if ( topdown )
directorys.push_front(name);
else
directorys.push_back(name);
str _dir_entry(_path_file + name);
// 进入目录再次遍历
walk(_dir_entry, rtn_list);
}
else {
files.push_back(name);
}
}
if ( topdown )
rtn_list.push_front(make_tuple(path, directorys, files));
else
rtn_list.push_back(make_tuple(path, directorys, files));
FindClose(handle);
}
}
}
return;
}
// 格式化输出结果
void format_result( walk_list& res ) {
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsole(hStdOut, _T("["), 1, NULL, NULL);
// 输出字符串
auto f_print_str = [&](str& s)->void {
WriteConsole(hStdOut, _T("\""), 1, NULL, NULL);
WriteConsole(hStdOut, s.c_str(), s.length(), NULL, NULL);
WriteConsole(hStdOut, _T("\""), 1, NULL, NULL);
};
// 输出列表元素
auto f_print_list = [&](list<str>& v)->void {
WriteConsole(hStdOut, _T("["), 1, NULL, NULL);
for_each(v.begin(), v.end(),
[&](str& s)->void{f_print_str(s);
WriteConsole(hStdOut, _T(","), 1, NULL, NULL);});
WriteConsole(hStdOut, _T("]"), 1, NULL, NULL);
};
// 输出元组元素
auto f_print_tuple = [&](walk_list_element_type& v)->void {
WriteConsole(hStdOut, _T("("), 1, NULL, NULL);
// 输出目录
f_print_str(std::get<0>(v));
WriteConsole(hStdOut, _T(","), 1, NULL, NULL);
// 输出子目录
f_print_list(std::get<1>(v));
WriteConsole(hStdOut, _T(","), 1, NULL, NULL);
// 输出目录下的子文件
f_print_list(std::get<2>(v));
WriteConsole(hStdOut, _T(")"), 1, NULL, NULL);
};
// 遍历walk_list列表
for_each(res.begin(), res.end(),
[&](walk_list_element_type& v)->void{f_print_tuple(v);
WriteConsole(hStdOut, _T(",\n"), 2, NULL, NULL);});
WriteConsole(hStdOut, _T("]"), 1, NULL, NULL);
return;
}
int main( int argc, char* argv[] ) {
str note(_T("输入要遍历的目录(量力而行): "));
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), note.c_str(), note.length(), NULL, NULL);
str path;
get_input(path);
// 规范输入的路径
for ( auto it = path.begin(); it != path.end(); ++it) {
if ( *it == '/' ) {
*it = '\\';
}
}
while ( path.back() == '\\' )
path.pop_back();
// 将"."转换成当前运行路径
if ( path.length() == 1 && path == '.' ) {
TCHAR buf;
GetCurrentDirectory(MAX_PATH, buf);
path = str(buf);
}
/// 用来接收结果
walk_list rtn;
walk(path, rtn, true);
format_result(rtn);
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), _T("\n"), 1, NULL, NULL);
system("pause");
return 0;
}
简单的测试,可绝对路径,相对路径
附上附件(源代码以及编译好的二进制可执行文件)
很不错,值得学习!
页:
[1]