吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2396|回复: 1
收起左侧

[Python 原创] [WIN32|STL]C++实现python的os模块的walk函数

[复制链接]
lovingxiaobing 发表于 2019-2-22 19:31


大家在学习python过程中,应该也遇到使用遍历目录的功能。可能是作业或者其他的,既然是python,肯定是用轮子就对了!!
在python中,遍历一个目录可以使用,os.list配合os.chdir一起使用遍历目录,但是这可是python,还有一个函数就是os.walk。


先放一张图来装X~~~上面有walk函数的用途,以及每个参数的含义。


python-help.png


粗略来说就是:给定一个目录,然后walk函数去遍历它。遍历的结果为目录,也有可能是文件,结果会以(目录字符串,子目录名字符串列表,目录下文件名字符串列表)这样的元组的方式存在一张列表里。
ok!这就是功能与要求,额外的功能就是这些个元素按照怎么样的顺序存在这个结果列表里(源代码中的topdown)。


下面是全部源代码:
[C++] 纯文本查看 复制代码
/***************************************************
 *  作者: 小冰
 *  邮箱: [email]lovingxiaobing@qq.com[/email]
 *  备注: [C++] 遍历目录的结果保存到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[0] == '.' ) {
        TCHAR buf[MAX_PATH];
        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;
}



简单的测试,可绝对路径,相对路径
result.png


附上附件(源代码以及编译好的二进制可执行文件)
遍历[目录和文件](功能与python的os.walk一样).zip (12.22 KB, 下载次数: 4)

免费评分

参与人数 1吾爱币 +3 热心值 +1 收起 理由
苏紫方璇 + 3 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

yntcxlong 发表于 2019-2-22 22:43 来自手机
很不错,值得学习!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-21 07:44

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表