设为首页 收藏本站
查看: 452|回复: 0

[经验分享] linux下遍历目录

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-2-24 13:34:38 | 显示全部楼层 |阅读模式
遍历目录的主要思想
  由于目录就是一颗树,所以遍历目录就转换为遍历一棵树。谈到树的遍历就再熟悉不过了,有树的前序、层次和后序遍历,我使用的是前序遍历,后序遍历和前序遍历本质上一样,而层次遍历要比前两个麻烦些,我两个都实现了,现在贴出来分享下。

前序遍历
  前序遍历和树的遍历一样,我先显示当前目录的信息,然后遍历目录中的目录项,如果目录项是一个目录则先递归这个子目录,否则如果是目录项是非目录的话就返回。


static void DoTraverDir(MyFunc myFunc)
{
    struct stat statBuf;
    DIR *pDir;
    struct dirent *pDirent;
    int pathLen, direntLen;

//    printf("path: %s\n", fullPath);
    //获取当前目录信息,用lstat防止嵌套调用
    if (lstat(fullPath, &statBuf) == 0)
        myFunc(fullPath, &statBuf, TD_F);
    else
    {
        myFunc(fullPath, &statBuf, TD_NS);  //无法获取信息
        return;
    }
    if (!S_ISDIR(statBuf.st_mode))  //当前路径为文件
        return;

    //处理目录
    pathLen = strlen(fullPath);
    if (pathLen >= MAX_PATH - 2)  //目录长度限制,不再处理更深层的目录
        return;
    if ((pDir = opendir(fullPath)) == NULL)
    {
        myFunc(fullPath, &statBuf, TD_DNR);  //无法读取目录
        return;
    }
    if (fullPath[pathLen - 1] != '/')
        fullPath[pathLen++] = '/';
    //遍历目录中的所有目录项
    while ((pDirent = readdir(pDir)) != NULL)  
    {
        //忽略.和..目录项
        if (strcmp(pDirent->d_name, ".") == 0 ||
            strcmp(pDirent->d_name, "..") == 0)
            continue;
        direntLen = strlen(pDirent->d_name);
        if (pathLen +  direntLen > MAX_PATH)  //路径超过了最大长度
            return;
        strcpy(fullPath + pathLen, pDirent->d_name);
        fullPath[pathLen +  direntLen] = 0;
        DoTraverDir(myFunc); //递归处理下一层
    }
    fullPath[pathLen - 1] = 0;
    if (closedir(pDir) == -1)
        printf("close dir error : %s\n", fullPath);
}

  代码中的fullPath是一个全局变量,用来存放当前遍历文件的路径,路径的最大长度为4096,超过了4096函数自己返回,不进行任何的处理,定义如下:

1 #define MAX_PATH 4096
2 static char fullPath[MAX_PATH + 1];
  还有一个地方值得注意,那就是我上面红色标识的代码,遍历完目录后必须将当前目录关闭掉,否则程序占有的打开目录资源会超过系统的限制,当遍历到了一定的数量后,后面的遍历都会失败,我就是开始没有关闭目录,所以后面出现莫名其妙的错误。

层次遍历
  层次遍历要比前序遍历复杂点,因为是要先处理好了当前目录中的所有目录项后再处理下一层的目录。所有在遍历当前目录的目录项时必须保存下层目录的路径信息,以方便处理下层目录。不过和前面代码的实现也差不多,就是多了一个保存路径的容器罢了,代码如下:


static void DoTraverDir(MyFunc myFunc)
{
    struct stat statBuf;
    DIR *pDir;
    struct dirent *pDirent;
    int pathLen, direntLen;
    std::vector<std::string> vpDirent;
    std::vector<std::string>::iterator vpDirentIterator;
    std::string str;

//    printf("path: %s\n", fullPath);        
    //获取当前目录信息,用lstat防止嵌套调用
    if (lstat(fullPath, &statBuf) == 0)
        myFunc(fullPath, &statBuf, TD_F);
    else
    {
        myFunc(fullPath, &statBuf, TD_NS);  //无法获取信息
        return;
    }
    //处理目录
    pathLen = strlen(fullPath);
    if (pathLen >= MAX_PATH - 2)  //目录长度限制,不再处理更深层的目录
        return;
    if ((pDir = opendir(fullPath)) == NULL)
    {
        myFunc(fullPath, &statBuf, TD_DNR);  //无法读取目录
        return;
    }
    if (!S_ISDIR(statBuf.st_mode))  //当前路径为文件
            return;
    if (fullPath[pathLen - 1] != '/')
        fullPath[pathLen++] = '/';
    //遍历目录中的所有目录项

    while ((pDirent = readdir(pDir)) != NULL)  
    {
        //忽略.和..目录项
        if (strcmp(pDirent->d_name, ".") == 0 ||
            strcmp(pDirent->d_name, "..") == 0)
            continue;
        direntLen = strlen(pDirent->d_name);
        if (pathLen +  direntLen > MAX_PATH)  //路径超过了最大长度
            return;
        strcpy(fullPath + pathLen, pDirent->d_name);
        fullPath[pathLen +  direntLen] = 0;
        if (lstat(fullPath, &statBuf) != 0)
        {
            myFunc(fullPath, &statBuf, TD_NS);  //无法获取信息
            continue;
        }
        if (S_ISDIR(statBuf.st_mode))  //当前路径为目录
            vpDirent.push_back(pDirent->d_name);
        else
            myFunc(fullPath, &statBuf, TD_F);
    }
    if (closedir(pDir) == -1)
    {
        fullPath[pathLen - 1] = 0;
        printf("close dir error : %s\n", fullPath);
    }

    for (vpDirentIterator = vpDirent.begin(); vpDirentIterator != vpDirent.end(); ++vpDirentIterator)
    {
        str = *vpDirentIterator;
        direntLen = str.length();
        strcpy(fullPath + pathLen, str.c_str());
        fullPath[pathLen +  direntLen] = 0;
        DoTraverDir(myFunc);
    }
}

回调函数
  上面程序中的回调函数MyFunc是用来显示每个文件的信息和对所遍历信息的统计,下面是该函数的具体实现:


void ShowInfo(const char *pathName, const struct stat *statBuf, int type)
{
    switch (type)
    {
        case TD_F:
            if (S_ISREG(statBuf->st_mode))  //普通文件
                nReg++;
            else if (S_ISDIR(statBuf->st_mode))  //目录
                nDir++;
            else if (S_ISCHR(statBuf->st_mode))  //字符文件
                nChr++;
            else if (S_ISBLK(statBuf->st_mode))  //块文件
                nBlk++;
            else if (S_ISFIFO(statBuf->st_mode))  //管道文件
                nFifo++;
            else if (S_ISLNK(statBuf->st_mode))  //链接文件
                nLink++;
            else if (S_ISSOCK(statBuf->st_mode))  //套接字文件
                nSock++;
            else  //未知文件类型
            {
                nKno++;
                printf("unknow file type : %s\n", pathName);
            }
            break;
        case TD_NS:
            nNs++;
            printf("can't state file : %s\n", pathName);   
            break;
        case TD_DNvoid ShowInfo(const char *pathName, const struct stat *statBuf, int type)
{
    switch (type)
    {
        case TD_F:
            if (S_ISREG(statBuf->st_mode))  //普通文件
                nReg++;
            else if (S_ISDIR(statBuf->st_mode))  //目录
                nDir++;
            else if (S_ISCHR(statBuf->st_mode))  //字符文件
                nChr++;
            else if (S_ISBLK(statBuf->st_mode))  //块文件
                nBlk++;
            else if (S_ISFIFO(statBuf->st_mode))  //管道文件
                nFifo++;
            else if (S_ISLNK(statBuf->st_mode))  //链接文件
                nLink++;
            else if (S_ISSOCK(statBuf->st_mode))  //套接字文件
                nSock++;
            else  //未知文件类型
            {
                nKno++;
                printf("unknow file type : %s\n", pathName);
            }
            break;
        case TD_NS:
            nNs++;
            printf("can't state file : %s\n", pathName);   
            break;
        case TD_DNR:
            nDnr++;
            printf("can't open dir : %s\n", pathName);
            break;
        default:
            printf("unkonw type\n");
    }
}R:
            nDnr++;
            printf("can't open dir : %s\n", pathName);
            break;
        default:
            printf("unkonw type\n");
    }
}


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-15190-1-1.html 上篇帖子: Ubuntu下把缺省的dash修改为bash 下篇帖子: centos 用dvd创建yum 仓库 linux
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

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